React Native封裝Android原生UI和Android原生模塊,並且集成騰訊雲點播的Android SDK

  今天記錄一下我的一個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, justifyContent:'center', alignItems:'center',
				     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);



程序顯示效果圖:





























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章