美文网首页Android开发
[React-native]RN调用原生的深坑-For Andr

[React-native]RN调用原生的深坑-For Andr

作者: 蜗牛学开车 | 来源:发表于2018-10-16 15:36 被阅读5次

    前言:最近闲着没事来搞一波RN学习,搞了一个Demo练习一把。在RN调用原生启动原生页面时入了深坑(虽然前面也遇到很多的坑,信我,这个是最深的)。

    **下面来看下网上的实现方式吧(我看了至少20篇博客以及1个视频教程,基本都是这么做的):

    第一步:声明自定义ReactContextBaseJavaModule

    用AndroidStudio打开你已经init好的项目(注意:是Android项目,init好之后会有Android和ios两个项目。),然后声明一个类继承ReactContextBaseJavaModule,示例代码如下:

    public class ReactNativeModule extends ReactContextBaseJavaModule {
        private ReactContext reactContext;
    
        ReactNativeModule(ReactApplicationContext reactContext) {
            super(reactContext);
            this.reactContext = reactContext;
        }
    
        @Override
        public String getName() {
            return getClass().getSimpleName();
        }
    
        /**
         * 定义个给RN调用的接口,RN可以调用这个方法并传置。这里一定要加上@ReactMethod这个注解。
         * @param componentName 用来接收RN传递过来的数据。这里有几个参数分别是什么类型都看你的需求。
         */
        @ReactMethod
        public void openNativeVC(String componentName) {
            //调起原生页面
            CommonActivity.startRNPage(reactContext, componentName);
        }
    }
    

    ReactContextBaseJavaModule有一个抽象方法必须重写,返回这个Module的名称,建议与类名保持一致,就如示例代码中那样返回getClass().getSimpleName()

    第二步:声明自定义ReactPackage

    声明一个类实现ReactPackage接口,示例代码如下:

    public class NavigatorPackage implements ReactPackage {
        @Override
        public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
            return Arrays.<NativeModule>asList(new ReactNativeModule(reactContext));
        }
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    }
    

    上面这个一步主要是实现createNativeModules这个方法,将我们刚刚声明的ReactContextBaseJavaModule的子类ReactNativeModule给创建出来并存入List集合返回给调用者。

    第三步(注意:坑就在这一步):修改Application

    找到MainApplication(RN默认就是这个类名)这个Application的子类,在这个类里面你会发下下面这样一段代码:

     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()
                );
            }
        };
    

    在getPackages方法的返回值List中加入我们刚刚声明的ReactPackage的子类NavigatorPackage,改完之后代码如下:

     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(),
                        //加入我们自己声明的ReactPackage的子类。
                        new NavigatorPackage()
                );
            }
        };
    

    最后一步:在RN中调用

    首先导包:

    import {NativeModules} from 'react-native';
    

    然后在你需要调用的地方调用即可。

    NativeModules.ReactNativeModule.openNativeVC("RNDemo");
    

    什么?你报错了?是下面的这种错误吗?

    RN调原生错误

    如果你是上面的错误(undefined is not an object (evaluating '_reactNative.NativeModules.ReactNativeModule.openNativeVC'))那么恭喜你来对地方了。
    我说过了,坑就在第三步,把你Application中构建ReactNativeHost的代码换成下面的:

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    
            @Override
            protected ReactInstanceManager createReactInstanceManager() {
                if (reactInstanceManager == null) {
                    reactInstanceManager = ReactInstanceManager.builder()
                            .setApplication(MainApplication.this)
                            .setBundleAssetName("index.bundle")
                            .setJSMainModulePath("index")
                            .addPackages(ReactManager.getInstance().getReactInstanceManagerPackages())
                            .setUseDeveloperSupport(BuildConfig.DEBUG)
                            .setInitialLifecycleState(LifecycleState.RESUMED)
                            .build();
                }
                return reactInstanceManager;
            }
    
            @Override
            public boolean getUseDeveloperSupport() {
                return BuildConfig.DEBUG;
            }
    
            @Override
            protected List<ReactPackage> getPackages() {
                //重写了createReactInstanceManager方法后这里的返回值就没有什么意义了!所以这里直接返回空集合。
                return Collections.emptyList();
            }
    
            @Override
            protected String getJSMainModuleName() {
                return "index";
            }
        };
    

    重写createReactInstanceManager方法自己动手构建ReactInstanceManager,而ReactInstanceManager对象最好是全局唯一(单例)的,所有地方都使用你自己构建的这个唯一的ReactInstanceManager。至于为什么这样就好了?我这里就不多讲了,因为产品喊我过去过需求去了,此刻我的内心很高兴(xiang kan ren)的。大家去看下ReactNativeHost的源码就明白了。

    如果我的文章解决了你的问题,就请给个爱心(喜欢一下)。再见!!!。

    相关文章

      网友评论

        本文标题:[React-native]RN调用原生的深坑-For Andr

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