android rn动态技术,基于ReactNative实现动态加载

本文介绍了如何使用ReactNative实现在Android端动态加载模块。通过Spring Boot服务端提供接口,Android客户端获取并下载模块,利用React Native的离线打包功能,实现模块的离线访问。详细讲解了从环境搭建到服务端接口、React Native项目创建、Android端集成和动态加载的步骤。

背景

最近看到某厂Android端物联网Demo演示应用中可动态加载模块,具体操作是在控制台拖拽生成一个模块和链接地址。然后在Android端刷新首页即可看到新添加的模块。下载Demo代码之后发现用到了facebook开源的react-native框架。然后打算研究一下是否能模拟动态下发模块的效果。

于是决定从以下几个方面来实现这个过程。

1、服务端——实现首页接口及下载接口

服务端用Spring Boot来实现,Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。对于开发微服务非常便捷。

2、Android端——显示可加载的模块以及下载模块

即一个Android工程

3、两个动态下发的模块(jsbundle)

React Native实现

环境搭建

1、jdk

针对不同操作系统下载安装即可 下载地址

2、maven

Apache Maven,是一个软件(特别是Java软件)项目管理及自动构建工具,类似于Android中的Gradle。下载地址

3、nodejs

Node.js是一个基于Chrome V8引擎的JavaScript运行时。下载地址

4、android环境

大家都懂

5、react native

在终端执行npm install -g react-native-cli

部分可能需要手动配置环境变量,全部安装完成后,来看一下我本地各个软件的版本

jdk版本

$ java -version

java version "1.8.0_121"

复制代码

maven版本

$ mvn -v

Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00)

复制代码

node版本

$ node -v

v10.9.0

复制代码

react native 版本

$ react-native -v

react-native-cli: 2.0.1

react-native: 0.57.8

复制代码

Server开发

这部分比较简单,就三个接口。在spring.io初始化一个maven项目然后下载下来,用Eclipse或IntelliJ IDEA打开即可。

然后在pom.xml增加web配置

org.springframework.boot

spring-boot-starter-web

复制代码

增加以下三个接口

Android端获取首页配置

@RequestMapping(value = "/home", method = RequestMethod.GET)

react端获取bundle信息

@RequestMapping(value = "/bundle/{id}", method = RequestMethod.GET)

Android下载bundle

@RequestMapping(value = "/download/bundle/{name}", method = RequestMethod.GET, produces = "application/zip")

复制代码

接口的具体实现可以看源码,都比较简单。

React Native开发

初始化项目

react-native init AModel

复制代码

初始化完成之后可以用 react-native run-android看一下运行效果。直接运行会在本地起一个node server,这个时候访问的js bundle就是访问的这个server上的。我们创建两个项目分别是AModel和BModel。具体可以看源码,这里不是我们的重点。

离线打包

这一步是把之前从node server访问的js文件打成离线包,方便动态加载,打包命令如下:

react-native AModel --entry-file index.js --bundle-output ./AModel/AModel.bundle --platform android --assets-dest ./bundle --dev false

react-native BModel --entry-file index.js --bundle-output ./BModel/BModel.bundle --platform android --assets-dest ./bundle --dev false

//entry-file JS文件的路径

//bundle-output JSbundle文件的生成目录

//platform 平台 Android或iOS

//assets-dest 资源文件的生成目录

//dev 开发模式

复制代码

然后把两个bundle分别打成zip包。

Android开发

仍然用react native生成一个工程,我们只用它的Android工程,之所以不直接使用Android Studio生成是为了使用react native添加好的"com.facebook.react:react-native:+"的依赖。

react-native init host

复制代码

创建好之后,删除MainApplication中多余的代码只保留以下代码。

public class MainApplication extends Application {

@Override

public void onCreate() {

super.onCreate();

SoLoader.init(this, /* native exopackage */ false);

}

}

复制代码

创建MainActivity,在进入主页之后调用接口,获取有哪些模块可以加载

private void getHomeInfo() {

OkHttpClient okHttpClient = new OkHttpClient();

//192.168.100.14是本地server的ip地址,保证手机和电脑在统一局域网

Request request = new Request.Builder().url("http://192.168.100.14:8080/home").method("GET", null).build();

Call call = okHttpClient.newCall(request);

call.enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, Response response) throws IOException {

HomeResponse homeResponse = new Gson().fromJson(response.body().string(), HomeResponse.class);

for (final HomeResponse.Bundle bundle : homeResponse.data) {

runOnUiThread(new Runnable() {

@Override

public void run() {

Button button = new Button(MainActivity.this);

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);

params.setMargins(10, 10, 10, 10);

button.setLayoutParams(params);

button.setText(bundle.desc);

button.setTextColor(Color.WHITE);

button.setBackground(getResources().getDrawable(R.drawable.bg));

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// 检查是否下载过,如果已经下载过则直接打开

String f = MainActivity.this.getFilesDir().getAbsolutePath() + "/" + bundle.name + "/" + bundle.name + ".bundle";

File file = new File((f));

if (file.exists()) {

DispatchUtils.dispatchModel = bundle.name;

DispatchActivity.start(MainActivity.this);

} else {

download(bundle.name);

}

}

});

linearLayout.addView(button);

}

});

}

}

});

}

复制代码

点击可加载的模块,如果已经下载过,则直接打开,否则下载后打开

try {

//下载之后解压,然后打开

ZipUtils.unzip(MainActivity.this.getFilesDir().getAbsolutePath() + "/" + bundleName + ".zip", MainActivity.this.getFilesDir().getAbsolutePath());

DispatchUtils.dispatchModel = bundleName;

DispatchActivity.start(MainActivity.this);

} catch (Exception e) {

e.printStackTrace();

}

复制代码

重点

这里的重点是,统一个模块分发的DispatchActivity作为入口,所有的模块打开都走这里。然后重写createReactActivityDelegate,这里面指定了要加载的模块的路径。

public class DispatchActivity extends ReactActivity {

public static void start(Context context) {

Intent starter = new Intent(context, DispatchActivity.class);

context.startActivity(starter);

}

@Override

protected ReactActivityDelegate createReactActivityDelegate() {

DispatchDelegate delegate = new DispatchDelegate(this, DispatchUtils.dispatchModel);

return delegate;

}

}

复制代码

public class DispatchDelegate extends ReactActivityDelegate {

private Activity activity;

private String bundleName;

public DispatchDelegate(Activity activity, @Nullable String mainComponentName) {

super(activity, mainComponentName);

this.activity = activity;

this.bundleName = mainComponentName;

}

@Override

protected ReactNativeHost getReactNativeHost() {

ReactNativeHost mReactNativeHost = new ReactNativeHost(activity.getApplication()) {

@Override

public boolean getUseDeveloperSupport() {

return BuildConfig.DEBUG;

}

@Override

protected List getPackages() {

return Arrays.asList(

new MainReactPackage()

);

}

@Nullable

@Override

protected String getJSBundleFile() {

// 这里指定JSBundleFile的入口,从而实现加载不同的模块

String file = activity.getFilesDir().getAbsolutePath() + "/" + bundleName + "/" + bundleName + ".bundle";

return file;

}

@Nullable

@Override

protected String getBundleAssetName() {

return bundleName + ".bundle";

}

@Override

protected String getJSMainModuleName() {

return "index";

}

};

return mReactNativeHost;

}

}

复制代码

运行效果如下:

format,png

format,png

format,png

├── AModel 模块A

├── BModel 模块B

├── host Android

└── rn-server 服务端

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值