美文网首页Android开发Android 开发笔记Android开发经验谈
Android项目集成RN系列:修改端口号 / 离线包 / 消息

Android项目集成RN系列:修改端口号 / 离线包 / 消息

作者: 闲庭 | 来源:发表于2018-11-18 22:00 被阅读6次

【简述RN集成到Android原生项目】

  1. 手动修改React Native端口号
  2. 将RN项目打包成离线包
  3. RN与Android原生的消息通信

不清楚Android项目如何集成RN,见【简述RN集成到Android原生项目】

1. 手动修改React Native端口号

  • 修改React Native Server端口号
    运行一个React Native项目的时候,React Native会启动一个默认端口号为8081的本地服务,该8081的服务就是React Native项目的一个本地服务器,用于提供JSBundle包和一些静态资源。
    • 临时修改Server端口号
      通过cmd执行yarn start --port=8082 或者npm run start --port=8082 .
    • 永久修改Server端口号
      在你的项目名称/node_modules/react-native/local-cli/server/server.js 找到server.js文件,打开后找到 module.exports -> options -> command: '--port [number]'修改对应的default的值。
      修改前:
       {
          command: '--port [number]',
          parse: (val: string) => Number(val),
          default: (config: ConfigT) => config.server.port,
        }
      
      修改后:
      {
        command: '--port [number]',
        parse: (val: string) => Number(val),
        default: 8082,
      }
      
  • 修改对应集成RN的Android 项目的端口号
    • 方案一:代码中在application或者主activity中做如下设置:
      @Override
      public void onCreate() {
          super.onCreate();
          SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
          mPreferences.edit().putString("debug_http_host","localhost:8082").commit();
      }
      
    • 方案二:React Native 会给 Android手机或者是虚拟机安装一个软件,就是你的软件,首先我们先打开这个软件,报错页面摇晃手机显示菜单,找到Dev Settings => 然后找到 Debug server host & port for device => 然后输入电脑的ip地址和端口 , 点击返回 => 页面是空白,再次点击摇一摇,选择Reload JS程序就显示出来了。

2. 打离线包,手动生成index.android.bundle 文件保存到assets 文件夹下或者本地存储文件夹中。

react-native bundle --entry-file index.android.js --platform android --dev false --bundle-output ./app/src/main/assets/index.android.bundle --assets-dest ./app/src/main/res/
  • --platform:平台
  • --dev:开发模式
  • --entry-file:条目文件
  • --bundle-output:bundle文件生成的目录
  • --assets-dest:资源文件生成的目录
    备注:
    react-native bundle --entry-file index.js --platform android --dev false --bundle-output ./app/src/main/assets/index.android.bundle --assets-dest ./app/src/main/res/
    不同业务对应的--entry-file文件不一样(有的是index.js,有的是index.android.js),打包时填写正确的入口文件名,并且--bundle-output输出的文件名也需要根据业务区分。
    查看打包命令
    react-native bundle -h

3. RN与Android原生的消息通信

  • 创建MyNativeModule.java
    package com.liujc.rnappdemo.hybride;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.support.annotation.Nullable;
    import android.text.TextUtils;
    import android.util.Log;
    import android.widget.Toast;
    
    import com.facebook.react.bridge.Callback;
    import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
    import com.facebook.react.bridge.Promise;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.bridge.ReactContextBaseJavaModule;
    import com.facebook.react.bridge.ReactMethod;
    import com.facebook.react.modules.core.DeviceEventManagerModule;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 类名称:MyNativeModule
     * 创建者:Create by liujc
     * 描述:原生预留给RN的调用方法
     */
    public class MyNativeModule extends ReactContextBaseJavaModule {
        public static final String REACT_NATIVE_CLASSNAME = "MyNativeModule";
        private ReactApplicationContext mContext;
        public static final String EVENT_NAME = "nativeCallRn";
        public static final String TAG = "TAG";
    
        public MyNativeModule(ReactApplicationContext reactContext) {
            super(reactContext);
            mContext = reactContext;
        }
    
        @Override
        public String getName() {
         //返回的这个名字是必须的,在rn代码中需要这个名字来调用该类的方法。
            return REACT_NATIVE_CLASSNAME;
        }
    
     //函数不能有返回值,因为被调用的原生代码是异步的,原生代码执行结束之后只能通过回调函数或者发送信息给rn那边。
        @ReactMethod
        public void rnCallNative(String msg){
            Toast.makeText(mContext,msg,Toast.LENGTH_SHORT).show();
        }
    
        @ReactMethod
        public void startActivityRN(String name, String params) {
            try {
                Activity activity = getCurrentActivity();
                if (activity != null) {
                    Class toClass = Class.forName(name);
                    Intent intent = new Intent(activity, toClass);
                    intent.putExtra("params", params);
                    activity.startActivity(intent);
                }
            } catch (Exception ex) {
                throw new JSApplicationIllegalArgumentException("不能打开Activity " + ex.getMessage());
            }
        }
         //后面该方法可以用Linking代替
        @ReactMethod  
        public void getDataFromIntent(Callback success, Callback error) {
            try {
                Activity currentActivity = getCurrentActivity();
                String result = currentActivity.getIntent().getStringExtra("result");//会有对应数据放入
                if (!TextUtils.isEmpty(result)) {
                    success.invoke(result);
                }
            } catch (Exception ex) {
                error.invoke(ex.getMessage());
            }
        }
    
        /**
         * Native调用RN
         * @param msg
         */
        public void nativeCallRn(String msg) {          
                mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(EVENT_NAME,msg);
        }
    
        /**
         * Callback 方式
         * rn调用Native,并获取返回值
         * @param msg
         * @param callback
         */
        @ReactMethod
        public void rnCallNativeFromCallback(String msg, Callback callback) {
    
            String result = "hello RN!Native正在处理你的callback请求";
            // .回调RN,即将处理结果返回给RN
            callback.invoke(result);
        }
    
        /**
         * Promise
         * @param msg
         * @param promise
         */
        @ReactMethod
        public void rnCallNativeFromPromise(String msg, Promise promise) {
            Log.e(TAG,"rnCallNativeFromPromise");
            String result = "hello RN!Native正在处理你的promise请求" ;
            promise.resolve(result);
        }
        /**
         * 向RN传递常量
         */
        @Nullable
        @Override
        public Map<String, Object> getConstants() {
            Map<String,Object> params = new HashMap<>();
            params.put("Constant","我是Native常量,传递给RN");
            return params;
        }
    }
    
  • 创建 MyReactPackage.java
    /**
    * 类名称:MyReactPackage
    * 创建者:Create by liujc
    * 描述:RN包管理器
    */
    public class MyReactPackage implements ReactPackage {
    
        public MyNativeModule myNativeModule;
        @Override
        public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
            myNativeModule = new MyNativeModule(reactContext);
            List<NativeModule> modules = new ArrayList<>();
            //将我们创建NativeModule添加进原生模块列表中
            modules.add(myNativeModule);
            return modules;
        }
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            //该处后期RN调用原生控件或自定义组件时可用到
            return Collections.emptyList(); 
        }
    }
    
  • 将我们创建的MyReactPackage添加到我们在AppApplication中创建的ReactNativeHost中。
    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()
             );
         }
     };
    
  • 接下来我们在js文件中如何调用?
    'use strict';
    
    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      NativeModules,
      View,
      ToastAndroid,
      DeviceEventEmitter
    } from 'react-native';
    
    let title = 'React Native界面';
    
    class reactNative extends Component {
    
        /**加载完成*/
        componentWillMount() {
          let result = NativeModules.MyNativeModule.Constant;
          console.log('原生端返回的常量值为:' + result);
        }
    
       /**
        * 原生调用RN
        */
       componentDidMount() {
           DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{
                title = "React Native界面,收到数据:" + msg;
                ToastAndroid.show("发送成功", ToastAndroid.SHORT);
           })
       }
    
      /**
       * RN调用Native且通过Callback回调 通信方式
       */
       callbackComm(msg) {
           NativeModules.MyNativeModule.rnCallNativeFromCallback(msg,(result) => {
           ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT);
        })
       }
    
       /**
        * RN调用Native且通过Promise回调 通信方式
        */
       promiseComm(msg) {
           NativeModules.MyNativeModule.rnCallNativeFromPromise(msg).then(
            (result) =>{
                ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT)
            }
        ).catch((error) =>{console.log(error)});
    }
    
      /**
       * 调用原生代码
       */
       call_button(){
              NativeModules.MyNativeModule.rnCallNative('调用原生方法操作');
       }
    
      callNative(){
           NativeModules.MyNativeModule.startActivityRN('com.liujc.rnappdemo.MyRNActivity','test');
      }
    
     render() {
          return ( 
        <View style={styles.container}>
              <Text style={styles.welcome} >
               {title}
              </Text>
    
              <Text style={styles.welcome}
              onPress={this.call_button.bind(this)}
              >
                React Native 调用原生方法操作!
              </Text>
    
             <Text style={styles.welcome}
                    //给此处的文字绑定一个事件,其中callNative为要调用的方法名。
                      onPress={this.callNative.bind(this)}>
                      跳转MyRNActivity!
              </Text>
    
             <Text style={styles.welcome} onPress={this.callbackComm.bind(this,'callback发送啦')}>
                Callback通信方式
             </Text>
             <Text style={styles.welcome} onPress={this.promiseComm.bind(this,'promise发送啦')}>
                Promise通信方式
             </Text>
         </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('reactNative', () => reactNative);
    
    

相关文章

网友评论

    本文标题:Android项目集成RN系列:修改端口号 / 离线包 / 消息

    本文链接:https://www.haomeiwen.com/subject/urcnfqtx.html