React Native客户端服务器分开集成方案

来源:互联网 发布:苹果 淘宝 编辑:程序博客网 时间:2024/06/05 07:55

刚刚接触React Native,发现网上在原有项目上集成RN时总是把Server和native代码混在一起,这样子很难维护,所以我们要想办法把server的代码和native的代码分开处理。

如何分开集成呢?

构建客户端

1.在我们Android项目中,可以新建一个RNLib的module,在其中的build.gradle中配置如下(这个是已经解决了后边碰到的问题的最终结果,大家如果在集成时遇到了问题可以参考下边这个文件):

apply plugin: 'com.android.library'android {    compileSdkVersion 23    buildToolsVersion "23.0.2"    defaultConfig {        minSdkVersion 15        targetSdkVersion 23        versionCode 1        versionName "1.0"        ndk{            abiFilters "armeabi-v7a", "x86"        }    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }}dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    compile ( "com.facebook.react:react-native:+",{        exclude group: 'com.android.support',module:'recyclerview-v7'        exclude group:'com.android.support',module:'support-v4'    })}
然后可以新建一个Activity,用于承载RN的页面:

package com.xx.xx;import android.app.Activity;import android.content.Intent;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import com.facebook.react.BuildConfig;import com.facebook.react.ReactInstanceManager;import com.facebook.react.ReactRootView;import com.facebook.react.common.LifecycleState;import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;import com.facebook.react.shell.MainReactPackage;public class MainActivity extends Activity        implements DefaultHardwareBackBtnHandler {    private ReactRootView mReactRootView;    private ReactInstanceManager mReactInstanceManager;    private LifecycleState mLifecycleState            = LifecycleState.BEFORE_RESUME;    @Override    protected void onCreate( Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            if (!Settings.canDrawOverlays(this)) {                Intent serviceIntent = new Intent(                        Settings.ACTION_MANAGE_OVERLAY_PERMISSION);                startActivity(serviceIntent);            }        }        mReactRootView = new ReactRootView(this);        mReactInstanceManager = ReactInstanceManager.builder()                .setApplication(getApplication())                .setBundleAssetName("index.android.bundle")                .setJSMainModuleName("index.android")                .addPackage(new MainReactPackage())                .setUseDeveloperSupport(BuildConfig.DEBUG)                .setInitialLifecycleState(mLifecycleState)                .build();        mReactRootView.startReactApplication(mReactInstanceManager,                "HelloWorld", null);        setContentView(mReactRootView);    }    @Override    protected void onPause() {        super.onPause();        mLifecycleState = LifecycleState.BEFORE_RESUME;        if (mReactInstanceManager != null) {            mReactInstanceManager.onHostPause();        }    }    @Override    protected void onResume() {        super.onResume();        mLifecycleState = LifecycleState.RESUMED;        if (mReactInstanceManager != null) {            mReactInstanceManager.onHostResume(this, this);        }    }    @Override    protected void onDestroy() {        super.onDestroy();        mReactRootView.unmountReactApplication();        mReactRootView = null;        if (mReactInstanceManager != null) {            mReactInstanceManager.destroy();        }    }    @Override    public void onActivityResult(int requestCode, int resultCode,                                 Intent data) {        if (mReactInstanceManager != null) {            mReactInstanceManager.onActivityResult(this,requestCode,                    resultCode, data);        }    }    @Override    public void onBackPressed() {        if (mReactInstanceManager != null) {            mReactInstanceManager.onBackPressed();        }        else {            super.onBackPressed();        }    }    @Override    public void invokeDefaultOnBackPressed() {        super.onBackPressed();    }}

别忘记在Manifest文件中声明该Activity。接下来我们只需要在我们的原生Android项目中对应需要跳转的位置加上Intent跳转即可。

这期间,你可能遇到的坑有:



1.最低版本sdk兼容问题
Error:Execution failed for task ':rnlib:processDebugAndroidTestManifest'.
> java.lang.RuntimeException: Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 16 declared in library [com.facebook.react:react-native:0.37.0] D:\MyProject\rnlib\build\intermediates\exploded-aar\com.facebook.react\react-native\0.37.0\AndroidManifest.xml
Suggestion: use tools:overrideLibrary="com.facebook.react" to force usage
解决办法:可以提示在app中的Manifest文件中的use tools添加接下来我们只需要将原生项目拷贝到Android文件夹下即可。 use tools:overrideLibrary="com.facebook.react"。如果原来就已经有其他overrideLibrary的话,只需要在后边追加即可。


2.v7包和v4包和你项目中的引用重复了。

解决办法:

接下来我们只需要将原生项目拷贝到Android文件夹下即可。

 compile ( "com.facebook.react:react-native:+",{        exclude group: 'com.android.support',module:'recyclerview-v7'        exclude group:'com.android.support',module:'support-v4'    })
在集成react-native包时exclude重复的包,常见的是v7包。接下来我们只需要将原生项目拷贝到Android文件夹下即可。接下来我们只需要将原生项目拷贝到Android文件夹下即可。

3.Error:Execution failed for task ':58moneybox-app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.8.0_91\bin\java.exe'' finished with non-zero exit value 2
这个问题大部分也是资源重复的问题,我当时时排除了v7包,但是v4包并没有报接下来我们只需要将原生项目拷贝到Android文件夹下即可。
duplicate的问题,而是报了这个,搜了好多资料。尝试排除v4就可以了。
如果还不可以那么进行如下操作:
1.查看是否有重复导入的jar包
2.修改builde.gradle buildToolsVersion "23.0.2" 改为 最新版
3.builder.gradle 下添加 defaultConfig {
       .....       
       multiDexEnabled true
        .....
    }

    dexOptions {
        incremental true
        javaMaxHeapSize "4g"
    }
另外如果使用了最新的build tools    compilesdk也要使用最新的 依赖的support也使用最新的  三者要保持一致


4.Error:(12, 0) Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
<a href="openFile:D:\58moneybox-react_native-2.2.0\rnlib\build.gradle">Open File</a>
这个提示也非常明显,在gradle.properties中添加android.useDeprecatedNdk=true.



5.如果这样做,总是提示RN中的类找不到,那么你看一下你引用的RN中的类是否真的不存在。

我当时碰到的情况是本地下载的react-native对应的aar总是0.20.0的包,而代码里用到的类却是0.37.0的包,后来想了半天,才想到是本地maven仓库的事儿,然后我将后边服务器端构建时生成的RNServer\node_modules\react-native\android\com\facebook\react\react-native\0.37.0这个目录复制到maven仓库,然后运行,发现真的可以了,会重新下载0.37.0对应的aar包。


6.当我们运行时,发现有些x86手机会找不到其他你用到的so,这是因为rn中有些只有x86和v7的so,而so的原理是一旦有对应的文件夹,就会去这个文件夹下找所有对应的so,当其他第三方的so不足时,我们就需要对rn做改造。将rn中相关的so拷贝到项目总,然后添加so过滤。
方法如下:

添加so过滤:
ndk {
abiFilters "armeabi"
}

sourceSets {
    main {
      jniLibs.srcDirs = ['libs']
    }
}


安装我们对应的包,等服务器端搭建好后,我们来测试结果。

构建服务器端:

如果您还没有RN环境,可以参考中文官网,先构建环境:http://reactnative.cn/docs/0.38/getting-started.html#content。

接下来就是在你要构建server的目录下运行

react-native init AwesomeProjectcd AwesomeProjectreact-native run-android


接下来我们只需要将原生项目拷贝到Android文件夹下即可。运行npm start。

我们打开调用我们RNActivity的地方,发现报错了。



1.Java.lang.RuntimeException: Could not get BatchedBridge, make sure your bundle is packaged correctly
解决方案:

[java] view plain copy
  1. react-native bundle —platform android —dev false —entry-file index.android.js —bundle-output MyYhao/app/src/main/assets/index.android.bundle —sourcemap-output MyYhao/app/src/main/assets/index.android.map —assets-dest MyYhao/app/src/main/res/  
react-native bundle —platform android —dev false —entry-file index.android.js —bundle-output  MyProject/app/src/main/assets/index.android.bundle —sourcemap-output
MyProject/app/src/main/assets/index.android.map —assets-dest MyProject/app/src/main/res/

注意assets的目录,我是在里面直接新建了index.android.bundle和index.android.map两个空文件,然后运行的,会自动往里面写入代码,然后运行就可以了


2.我们摇一摇发现调不出调试页面,打开悬浮窗权限仍然是不可以。经过查看才发现我们的RNActivity中原本设置的setUseDeveloperSupport(DebugConfig.Debug),

DebugConfig.Debug返回的值为false,我们将setUseDeveloperSupport方法的参数传为true即可。


接下来运行,发现终于可以正常开发RN了,欢呼吧。在RN开发中会遇到各种坑,需要大家耐心下来一点点攻克。

0 1
原创粉丝点击