今天记录一下我的一个React Native Demo:
具体实现了对Android原生UI的封装和Android原生模块的封装,并且集成腾讯云点播的Android SDK。
功能:第一个页面显示腾讯云点播的视频播放控件,并播放一段视频。点击视频控件跳转到第二个页面。
步骤:
一、创建React Native项目;
react-native init TestDemo
二、封装Android原生模块;
在TestDemo/android下创建一个GoToActivity.java文件,此类继承ReactContextBaseJavaModule,实现其中的方法。
三、封装Android原生UI;
在TestDemo/android下创建一个自定义View,命名为CustomView;
再创建一个ReactCustomViewManager.java文件,此类继承SimpleViewManager<CustomView>,泛型是我上面自定义的View,目的就是封装这个自定义View,给React Native使用。
四、把写好的原生模块、原生UI进行注册;
在TestDemo/android下创建一个MyReactPackage.java文件,此类继承ReactPackage,实现其中的方法,在createNativeModules方法中注册原生模块,在createViewManagers方法中注册原生UI。然后把MyReactPackage注册到MyApplication中getPackages方法中。
五、下载腾讯云点播Android SDK(下载地址:http://download-1252463788.cossh.myqcloud.com/RTMPSDKAndroid2.0.2.2801.zip);
将SDK的jniLibs文件夹拷贝到TestDemo/android/app/src/main/下;
导入jar包,在Android Studio工程中找到刚才的jniLibs目录,展开目录,可以看到txrtmpsdk.jar,点击右键选择“Add As Library...”;
在AndroidManifest.xml中配置APP的权限,音视频类APP一般需要以下权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.RECORD_AUdio" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.Camera"/>
<uses-feature android:name="android.hardware.camera.autofocus" />
六、在自定义View--CustomView的布局中加入腾讯云点播的播放控件com.tencent.rtmp.ui.TXCloudVideoView;
七、在JS端封装原生模块、原生UI,然后写一个页面进行测试。
源代码如下:
MainActivity.java
- package com.yb;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
- import com.facebook.react.ReactActivity;
- import org.greenrobot.eventbus.EventBus;
- import org.greenrobot.eventbus.Subscribe;
- import org.greenrobot.eventbus.ThreadMode;
- public class MainActivity extends ReactActivity {
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "yb";
- }
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- EventBus.getDefault().register(this);
- }
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void getMqttMessage(String mqttMessage) {
- Log.d("123pp",mqttMessage);
- startActivity(new Intent(this,SecondActivity.class));
- }
- @Override
- protected void onDestroy()
- {
- EventBus.getDefault().unregister(this);
- super.onDestroy();
- }
- }
MainApplication.java
- package com.yb;
- import android.app.Application;
- import com.facebook.react.ReactApplication;
- import com.facebook.react.ReactNativeHost;
- import com.facebook.react.ReactPackage;
- import com.facebook.react.shell.MainReactPackage;
- import com.facebook.soloader.SoLoader;
- import java.util.Arrays;
- import java.util.List;
- public class MainApplication extends Application implements ReactApplication
- {
- private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this)
- {
- @Override
- public boolean getUseDeveloperSupport()
- {
- return BuildConfig.DEBUG;
- }
- @Override
- protected List<ReactPackage> getPackages()
- {
- return Arrays.<ReactPackage>asList(
- new MainReactPackage(),new MyReactPackage()
- );
- }
- };
- @Override
- public ReactNativeHost getReactNativeHost()
- {
- return mReactNativeHost;
- }
- @Override
- public void onCreate()
- {
- super.onCreate();
- SoLoader.init(this,/* native exopackage */ false);
- }
- }
GoToActivity.java
- package com.yb;
- import com.facebook.react.ReactActivity;
- import android.widget.Toast;
- import com.facebook.react.bridge.NativeModule;
- import com.facebook.react.bridge.ReactApplicationContext;
- import com.facebook.react.bridge.ReactContext;
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
- import com.facebook.react.bridge.ReactMethod;
- import org.greenrobot.eventbus.EventBus;
- import java.util.Map;
- import java.util.HashMap;
- public class GoToActivity extends ReactContextBaseJavaModule
- {
- private static final String DURATION_SHORT_KEY = "SHORT";
- private static final String DURATION_LONG_KEY = "LONG";
- public GoToActivity(ReactApplicationContext reactContext)
- {
- super(reactContext);
- }
- /**
- * getName方法。这个函数用于返回一个字符串名字,就是js中的模块名
- */
- @Override
- public String getName()
- {
- return "GoToActivity";
- }
- /**
- * 返回了需要导出给JavaScript使用的常量
- */
- @Override
- public Map<String,Object> getConstants()
- {
- final Map<String,Object> constants = new HashMap<>();
- constants.put(DURATION_SHORT_KEY,Toast.LENGTH_SHORT);
- constants.put(DURATION_LONG_KEY,Toast.LENGTH_LONG);
- return constants;
- }
- /**
- * 导出给js使用的方法,需要使用注解@ReactMethod。方法的返回类型必须为void
- */
- @ReactMethod
- public void show(String message,int duration)
- {
- Toast.makeText(getReactApplicationContext(),message,duration).show();
- EventBus.getDefault().post(message);
- }
- }
CustomView.java
- package com.yb;
- import android.content.Context;
- import android.graphics.Color;
- import android.util.AttributeSet;
- import android.view.LayoutInflater;
- import android.widget.RelativeLayout;
- import android.widget.TextView;
- import com.tencent.rtmp.ui.TXCloudVideoView;
- /**
- * Created by Auser on 2017/5/2.
- */
- public class CustomView extends RelativeLayout
- {
- private TextView textView;
- private TXCloudVideoView txCloudVideoView;
- public CustomView(Context context)
- {
- super(context);
- init(context);
- }
- public CustomView(Context context,AttributeSet attrs)
- {
- super(context,attrs);
- init(context);
- }
- public CustomView(Context context,AttributeSet attrs,int defStyleAttr)
- {
- super(context,attrs,defStyleAttr);
- init(context);
- }
- private void init(Context context) {
- LayoutInflater.from(context).inflate(R.layout.customview_layout,this,true);
- textView = (TextView) this.findViewById(R.id.tv01);
- textView.setText("我是一个CustomView");
- textView.setTextColor(Color.parseColor("#ff0000"));
- txCloudVideoView = (TXCloudVideoView) this.findViewById(R.id.video_view);
- }
- public void setText(String txt) {
- this.textView.setText(txt);
- }
- public String getText() {
- return this.textView.getText().toString();
- }
- public TXCloudVideoView getTxCloudVideoView()
- {
- return txCloudVideoView;
- }
- public void setTxCloudVideoView(TXCloudVideoView txCloudVideoView)
- {
- this.txCloudVideoView = txCloudVideoView;
- }
- }
MyReactPackage.java
- package com.yb;
- import com.facebook.react.bridge.NativeModule;
- import com.facebook.react.bridge.ReactApplicationContext;
- import com.facebook.react.ReactPackage;
- import com.facebook.react.bridge.JavaScriptModule;
- import com.facebook.react.uimanager.ViewManager;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Collections;
- public class MyReactPackage implements ReactPackage
- {
- @Override
- public List<NativeModule> createNativeModules(
- ReactApplicationContext reactContext)
- {
- List<NativeModule> modules = new ArrayList<>();
- modules.add(new GoToActivity(reactContext));
- return modules;
- }
- @Override
- public List<Class<? extends JavaScriptModule>> createJSModules()
- {
- // TODO Auto-generated method stub
- return Collections.emptyList();
- }
- @Override
- public List<ViewManager> createViewManagers(
- ReactApplicationContext reactContext)
- {
- return Arrays.<ViewManager>asList(
- new ReactCustomViewManager()
- );
- }
- }
ReactCustomViewManager.java
- package com.yb;
- import android.support.annotation.Nullable;
- import android.util.Log;
- import android.webkit.WebView;
- import android.webkit.WebViewClient;
- import com.facebook.react.uimanager.SimpleViewManager;
- import com.facebook.react.uimanager.ThemedReactContext;
- import com.facebook.react.uimanager.annotations.ReactProp;
- import com.tencent.rtmp.TXLivePlayer;
- /**
- * Created by YiBing on 2017/4/28.
- */
- public class ReactCustomViewManager extends SimpleViewManager<CustomView>
- {
- ThemedReactContext context;
- public static final String REACT_CLASS = "RCTCustomView";
- @Override
- public String getName() {
- return REACT_CLASS;
- }
- @Override
- protected CustomView createViewInstance(ThemedReactContext reactContext) {
- this.context = reactContext;
- CustomView customView = new CustomView(reactContext);
- return customView;
- }
- @ReactProp(name = "url")
- public void setUrl(CustomView customView,@Nullable String url) {
- Log.e("TAG","setUrl");
- customView.setText(url);
- TXLivePlayer txLivePlayer = new TXLivePlayer(context);
- txLivePlayer.setPlayerView(customView.getTxCloudVideoView());
- txLivePlayer.startPlay(url,TXLivePlayer.PLAY_TYPE_VOD_MP4);
- }
- }
SecondActivity.java
- package com.yb;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import com.tencent.rtmp.ui.TXCloudVideoView;
- import com.tencent.rtmp.TXLivePlayer;
- public class SecondActivity extends AppCompatActivity
- {
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- }
- }
activity_second.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <TextView
- android:id="@+id/tv01"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Second Activity"
- android:gravity="center_horizontal"/>
- </RelativeLayout>
customview_layout.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/tv01"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Hello world!"
- android:gravity="center_horizontal"/>
- <com.tencent.rtmp.ui.TXCloudVideoView
- android:id="@+id/video_view"
- android:layout_below="@id/tv01"
- android:layout_marginTop="8dp"
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:layout_centerInParent="true"
- android:visibility="gone"/>
- </RelativeLayout>
CustomView.js
- /**
- * Created by YiBing on 2017/4/28.
- * react-native: 0.43.3
- * react-native-cli: 2.0.1
- */
- import { PropTypes } from 'react';
- import { requireNativeComponent,View } from 'react-native';
- var iface = {
- name: 'CustomView',propTypes: {
- url: PropTypes.string,...View.propTypes // include the default view properties
- },};
- module.exports = requireNativeComponent('RCTCustomView',iface);
GoToActivity.js
- /**
- * Created by YiBing on 2017/4/28.
- */
- 'use strict';
- import {
- NativeModules
- } from 'react-native';
- export default NativeModules.GoToActivity;
- // 以前的ES版本的写法。
- // var {NativeModules} = require('react-native');
- // module.exports = NativeModules.MyToast;
index.android.js
- import React,{ Component } from 'react';
- import {
- AppRegistry,StyleSheet,Text,View,ListView,TouchableOpacity,Image,ToastAndroid,} from 'react-native';
- import GoToActivity from './GoToActivity';
- import CustomView from './CustomView';
- var video_url = "http://www.zxx.net.cn:8080//dmmm/vedio/201612270541078235250/201612270541078235250.mp4";
- export default class yb extends Component {
- render() {
- return (
- <View style={styles.container}>
- <View style={{width:'100%',height:50,borderWidth:2,borderColor:'#f00',justifyContent:'center',alignItems:'center',}}>
- <Text style={{textAlign:'center',}}>腾讯云点播测试</Text>
- </View>
- <TouchableOpacity
- onPress={() => GoToActivity.show("Go To SecondActivity",ToastAndroid.SHORT)}
- style={{width:'100%',flex:1,borderWidth:10,borderColor:'#00f'}}>
- <CustomView
- url={video_url}
- style={{width:'100%',height:'100%'}} />
- </TouchableOpacity>
- </View>
- );
- }
- }
- const styles = StyleSheet.create({
- container: {
- flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF',},welcome: {
- fontSize: 20,textAlign: 'center',margin: 10,instructions: {
- textAlign: 'center',color: '#333333',marginBottom: 5,});
- AppRegistry.registerComponent('yb',() => yb);