react-native Android端开发打包 sdk 供第三方app调用详细教程

1. RN工程打包成 aar
现在有个项目需要我们做其他公司app的一部分功能,需要我以SDK 的形式集成到第三方app当中,由于我们之前是用的react-native 与原生混合开发,因此打包的方式与原生打包方式会有所不同,下面我来分享一下如何将rn开发的功能打成sdk(ps:不需要第三方app使用命令安装任何插件,尽可能的减少配置)。

现在我们需要将它打成aar包供总集成原生APP使用,具体流程如下图:

react-native Android端开发打包 sdk 供第三方app调用详细教程_第1张图片

总而言之,从RN工程提取出相关文件放在RN工程新建的module(Library)中,然后通过module(Library)进行打包出aar文件,最后直接提供给总集成app使用,下面具体介绍打包流程

1.将RN工程的相关文件及jar包等资源提取到RN工程新建的Module(Library)当中

提取部分总共3种资源,下面逐一说明:
首先我们先创建一个module

1.创建Module(Library)
首先创建一个Module(Library), 右键工程 =》 new =》 Module 弹出如下界面:
react-native Android端开发打包 sdk 供第三方app调用详细教程_第2张图片
选择 Android Library点击next,然后输入名称,包名信息,指定sdk版本为28(需要与第三方工程sdk版本一致),点击finish创建成功。
react-native Android端开发打包 sdk 供第三方app调用详细教程_第3张图片
2.bundle 文件
在cmd 终端定位到工程下,然后执行以下命令生成bundle包(记得一定要先创建一下assets文件夹):
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
然后将bundle文件连同 assets 文件夹复制到Module(Library)工程相同路径下,如下图:
react-native Android端开发打包 sdk 供第三方app调用详细教程_第4张图片

3.bundle打包后的静态资源文件
bundle打包后默认会在跟 assets 文件夹同级的res目录的drawable等文件夹下生成静态资源文件(如图片,html页面等),因此也需要将静态资源文件拷贝到Module(Library)工程相同路径下,如下图:

react-native Android端开发打包 sdk 供第三方app调用详细教程_第5张图片

4.RN核心依赖包
RN核心依赖包包括一个aar实体文件和相关依赖,首先需要从RN工程提取出依赖包,路径在node_modules/react-native/android/com/facebook/react/react-native/0.59.0下,如下图:
react-native Android端开发打包 sdk 供第三方app调用详细教程_第6张图片
将上图的两个文件拷贝出来,分别是:
react-native-0.59.0.arr
react-native-0.59.0.pom
其中pom文件需要处理一下,如下图:

<dependencies>
  <dependency>
    <groupId>com.facebook.infer.annotation</groupId>
    <artifactId>infer-annotation</artifactId>
    <version>0.11.2</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.android.support</groupId>
    <artifactId>appcompat-v7</artifactId>
    <version>28.0.0</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.facebook.fresco</groupId>
    <artifactId>fresco</artifactId>
    <version>1.10.0</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.facebook.fresco</groupId>
    <artifactId>imagepipeline-okhttp3</artifactId>
    <version>1.10.0</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.facebook.soloader</groupId>
    <artifactId>soloader</artifactId>
    <version>0.6.0</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>jsr305</artifactId>
    <version>3.0.2</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.12.1</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp-urlconnection</artifactId>
    <version>3.12.1</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>com.squareup.okio</groupId>
    <artifactId>okio</artifactId>
    <version>1.15.0</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

将上面的内容拷贝到记事本,并修改成以下内容备用:

implementation 'com.facebook.infer.annotation:infer-annotation:0.11.2'
implementation 'javax.inject:javax.inject:1'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.facebook.fresco:fresco:1.10.0'
implementation 'com.facebook.fresco:imagepipeline-okhttp3:1.10.0'
implementation 'com.facebook.soloader:soloader:0.6.0'
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.12.1'
implementation 'com.squareup.okio:okio:1.15.0'

先将react-native-0.59.0.arr 放入到Module(Library)工程中 libs目录下,如下图:
react-native Android端开发打包 sdk 供第三方app调用详细教程_第7张图片

然后在 mylibrary 目录下的 build.gradle 添加如下配置:

repositories {
    flatDir {
        dirs 'libs'
    }
}

然后在 dependencies 中添加

implementation(name:'react-native-0.59.0', ext:'aar')

最后将刚才备用在记事本的依赖配置也添加到 dependencies 中
最终展现形式如下图:

repositories {
    flatDir {
        dirs 'libs'
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.+'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation(name:'react-native-0.59.0', ext:'aar')
    implementation 'com.facebook.infer.annotation:infer-annotation:0.11.2'
    implementation 'javax.inject:javax.inject:1'
    implementation 'com.facebook.fresco:fresco:1.10.0'
    implementation 'com.facebook.fresco:imagepipeline-okhttp3:1.10.0'
    implementation 'com.facebook.soloader:soloader:0.6.0'
    implementation 'com.google.code.findbugs:jsr305:3.0.2'
    implementation 'com.squareup.okhttp3:okhttp:3.12.1'
    implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.12.1'
    implementation 'com.squareup.okio:okio:1.15.0'
}

5.Java 文件

此处为重点,RN工程,与原生工程调用方式略有区别,在MainActivity中写如何调用bundle的方法,如下图:

    public ReactRootView getReactRootView(String bundleName, String pathName, String moduleName,Bundle bundle){
        mReactRootView = new ReactRootView(this);
        ReactInstanceManagerBuilder builder = ReactInstanceManager.builder();
        builder.setApplication(this.getApplication());
        builder.setBundleAssetName(bundleName);
        builder.setJSMainModulePath(pathName);
        builder.addPackage(new MainReactPackage());
        builder.setUseDeveloperSupport(BuildConfig.DEBUG);
        builder.setInitialLifecycleState(LifecycleState.RESUMED);
        mReactInstanceManager = builder.build();//.setCurrentActivity(getActivity())
//注意这里的`moduleName`参数必须和工程名字,也是就是在`index.android.js`中AppRegistry.registerComponent()注册的名字一样
        mReactRootView.startReactApplication(mReactInstanceManager, moduleName, bundle);
        return mReactRootView;
    }

另外还需要将生命周期,回退事件等注入原生中,如下图:

@Override
public void invokeDefaultOnBackPressed() {
    super.onBackPressed();
}


@Override
public void onPause() {
    super.onPause();
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostPause();
    }
}

@Override
public void onResume() {
    super.onResume();
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostResume(this, this);
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostDestroy(this);
    }
}

//物理返回事件传递
@Override
public void onBackPressed() {
    super.onBackPressed();
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onBackPressed();
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode,resultCode,data);
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onActivityResult(this,requestCode,
                resultCode, data);
    }
}

最终在onCreate 方法中调用bundle 方法就可以了,如下图:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //向bundle传输数据
    Bundle bundle = new Bundle();
    bundle.putString("userId","01");
    mReactRootView = getReactRootView("index.android.bundle","index","AppProject",bundle);
    setContentView(mReactRootView);
}

最终的展现形式如下:

public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {

    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //向bundle传输数据
        Bundle bundle = new Bundle();
        bundle.putString("userId","01");
        mReactRootView = getReactRootView("index.android.bundle","index","AppProject",bundle);
        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }


    @Override
    public void onPause() {
        super.onPause();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy(this);
        }
    }

    //物理返回事件传递
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode,resultCode,data);
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onActivityResult(this,requestCode,
                    resultCode, data);
        }
    }

    public ReactRootView getReactRootView(String bundleName, String pathName, String moduleName,Bundle bundle){
        mReactRootView = new ReactRootView(this);
        ReactInstanceManagerBuilder builder = ReactInstanceManager.builder();
        builder.setApplication(this.getApplication());
        builder.setBundleAssetName(bundleName);
        builder.setJSMainModulePath(pathName);
        builder.addPackage(new MainReactPackage());
        builder.setUseDeveloperSupport(BuildConfig.DEBUG);
        builder.setInitialLifecycleState(LifecycleState.RESUMED);
        mReactInstanceManager = builder.build();//.setCurrentActivity(getActivity())
//注意这里的`moduleName`参数必须和工程名字,也是就是在`index.android.js`中AppRegistry.registerComponent()注册的名字一样
        mReactRootView.startReactApplication(mReactInstanceManager, moduleName, bundle);
        return mReactRootView;
    }
}

2.将Module(Library)打包成 aar 文件

1.修改 android 目录下的 gradle.properties
添加 aar 版本,以后版本控制直接修改这里就可以了

projectVersion = 1.1.0

2.修改 mylibrary 目录下的 build.gradle

添加打包命令,如下:

//动态修改aar名称
android.libraryVariants.all { variant ->
    if(variant.name.equalsIgnoreCase("release")) {
        variant.outputs.all { output ->
            def f = output.outputFileName
            if (f != null && f.endsWith('.aar')) {
                def fileName = "mylibrary-${projectVersion}.aar"
                output.outputFileName = fileName
            }
        }
    }else if(variant.name.equalsIgnoreCase("debug")) {
        variant.outputs.all { output ->
            def f = output.outputFileName
            if (f != null && f.endsWith('.aar')) {
                def fileName = "mylibrary-${projectVersion}-debug.aar"
                output.outputFileName = fileName
            }
        }
    }
}

3.执行导出 aar命令

1.点击右侧gradle = > :mylibrary = > Tasks => build => assemble 如下图
react-native Android端开发打包 sdk 供第三方app调用详细教程_第8张图片

执行成功后如下图:
react-native Android端开发打包 sdk 供第三方app调用详细教程_第9张图片
2. 导出的aar文件在 mylibrary\build\outputs\aar 目录下
react-native Android端开发打包 sdk 供第三方app调用详细教程_第10张图片
aar 文件中包含class,静态资源文件,bundle以及jar包等文件,至此导出aar文件完成。

2. 总集成app如何调用原生工程打包的aar文件

1.导入aar文件及相关依赖配置文件
将RN工程打包出的aar和 react-native-0.59.0.aar放入第三方app当中,如下:

react-native Android端开发打包 sdk 供第三方app调用详细教程_第11张图片
然后在 app 下的build.gradle 中添加配置:

repositories {
    flatDir {
        dirs 'libs'
    }
}

在dependencies 标签中添加

implementation (name: 'mylibrary-1.1.0',ext: 'aar')
implementation(name:'react-native-0.59.0', ext:'aar')

和RN核心包的依赖

implementation 'com.facebook.infer.annotation:infer-annotation:0.11.2'
implementation 'javax.inject:javax.inject:1'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.facebook.fresco:fresco:1.10.0'
implementation 'com.facebook.fresco:imagepipeline-okhttp3:1.10.0'
implementation 'com.facebook.soloader:soloader:0.6.0'
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.12.1'
implementation 'com.squareup.okio:okio:1.15.0'

2.在app下的AndroidManifest.xml 中添加相关配置

1.添加权限配置(一般第三方app都有权限配置),具体如下:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<!-- SD卡读取权限,用户写入离线定位数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>

2.在application中添加aar包中的activity配置,如下:

<activity android:name="com.example.libdemo.MainActivity"
    android:screenOrientation="portrait"></activity>

3.在总集成app中调用 arr 包中的方法
在 mainActivity 中添加调用 aar包中的方法,如下:

react-native Android端开发打包 sdk 供第三方app调用详细教程_第12张图片

红色方块就是aar包中的方法,此方法就是跳转到RN页面的。
注意:aar中的包名一定不要与总集app中的包名相同,否则容易造成调用混乱。

方法最终展示如下:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent in=new Intent();
        in.setClassName(this,"com.example.libdemo.MainActivity");
        startActivity(in);
        finish();
//        setContentView(R.layout.activity_main);
    }
}

至此,调用成功。

你可能感兴趣的:(react-native Android端开发打包 sdk 供第三方app调用详细教程)