概述

扩展原生能力指的是将您原生开发的功能通过一定规范暴露给 uni小程序环境,然后即可在 uni小程序应用中调用您的原生功能。

扩展方式

uni 原生端是基于 WeexSDK 来实现扩展原生能力,扩展原生能力有两种方式:一种是不需要参与页面布局,只需要通过 API 调用原生功能,比如:获取当前定位信息、数据请求等功能,这种情况可通过扩展module的方式来实现;另一种是需要参与页面布局,比如:map、image,这种情况需要通过扩展component即组件的方法来实现;

开发环境

注意事项

如果你扩展的ModuleComponent要与宿主进行数据交互需要注意。宿主与小程序不在同一进程,内存不共享。所以需要开发者自己实现跨进程通信。后续会完善此交互问题。

关于扩展的ModuleComponent代码中日志log。小程序运行在io.dcloud.unimp子进程。看日志log需要在这个进程看日志log。

扩展 module

下面以TestModule为例,源码请查看 uni小程序SDK 包中的示例 DEMO 工程;

1.创建Android Studio的Module模块

  • 在现有Android项目中创建library的Module。例如TestModule
  • 配置刚创建的Module的build.gradle信息。

    示例:

    1. //导入aar需要的配置
    2. repositories {
    3. flatDir {
    4. dirs 'libs'
    5. }
    6. }
    7. dependencies {
    8. //必须添加的依赖
    9. compileOnly 'com.android.support:recyclerview-v7:27.1.0'
    10. compileOnly 'com.android.support:support-v4:27.1.0'
    11. compileOnly 'com.android.support:appcompat-v7:27.1.0'
    12. compileOnly 'com.alibaba:fastjson:1.1.46.android'
    13. compileOnly fileTree(include: ['uniapp-release.aar'], dir: '../app/libs')
    14. }

    Tips:

    uniapp-release.aar是扩展module主要依赖库,必须导入此依赖库!

2.创建TestModule类

  • Module 扩展必须继承 WXModule 类

    示例:

    1. public class TestModule extends WXModule
  • 扩展方法必须加上@JSMethod (uiThread = false or true) 注解。Weex 会根据注解来判断当前方法是否要运行在 UI 线程,和当前方法是否是扩展方法。

  • Weex是根据反射来进行调用 Module 扩展方法,所以Module中的扩展方法必须是 public 类型。

    示例:

    1. //run ui thread
    2. @JSMethod(uiThread = true)
    3. public void testAsyncFunc(JSONObject options, JSCallback callback) {
    4. Log.e(TAG, "testAsyncFunc--"+options);
    5. if(callback != null) {
    6. JSONObject data = new JSONObject();
    7. data.put("code", "success");
    8. callback.invoke(data);
    9. }
    10. }
    11. //run JS thread
    12. @JSMethod (uiThread = false)
    13. public JSONObject testSyncFunc(){
    14. JSONObject data = new JSONObject();
    15. data.put("code", "success");
    16. return data;
    17. }
  • 同样因为是通过反射调用,Module 不能被混淆。请在混淆文件中添加代码:

    1. -keep public class * extends com.taobao.weex.common.WXModule{*;}
  • Module 扩展的方法可以使用 int, double, float, String, Map, List 类型的参数

3.注册TestModule

由于uni小程序运行在独立子进程中。内存与宿主不共享。所以宿主进程注册了TestModule,在uni小程序是无法使用的。 Android创建子进程时会主动再次初始化Application!所以uni小程序注册TestModule必须在Application中的onCreate初始化或注册。

Tips

  • 注册TestModule之前记得配置宿主的build.gradle导入Module模块.
  • 以下示例代码写在宿主的Application中。

示例:

  1. public class App extends Application {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. try {
  6. WXSDKEngine.registerModule("TestModule", TestModule.class);
  7. } catch (WXException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }

到此,我们已经完成了一个简单的 module 扩展

4. 在 uni小程序 中调用 module 方法

module 支持在 vue 和 nvue 中使用

示例:

  1. <template>
  2. <div>
  3. <button type="primary" @click="testAsyncFunc">testAsyncFunc</button>
  4. <button type="primary" @click="testSyncFunc">testSyncFunc</button>
  5. </div>
  6. </template>
  7. <script>
  8. // 获取 module
  9. var testModule = uni.requireNativePlugin("TestModule")
  10. export default {
  11. methods: {
  12. testAsyncFunc() {
  13. // 调用异步方法
  14. testModule.testAsyncFunc({
  15. 'name': 'unimp',
  16. 'age': 1
  17. },
  18. (ret) => {
  19. console.log(ret)
  20. })
  21. },
  22. testSyncFunc() {
  23. // 调用同步方法
  24. var ret = testModule.testSyncFunc({
  25. 'name': 'unimp',
  26. 'age': 1
  27. })
  28. console.log(ret)
  29. }
  30. }
  31. }
  32. </script>

Tips

uni.requireNativePlugin仅用于获取WXModule的对象。WXComponent不支持该方法!

扩展组件 component

下面以TestComponent为例,源码请查看 uni小程序SDK 包中的示例 DEMO 工程;

1.创建Android Studio的Module模块

请参考 扩展 Module

2.创建TestComponent类

  • Component 扩展类必须继承 WXComponent

    示例:

    1. public class TestText extends WXComponent<TextView>
  • WXComponent的initComponentHostView回调函数。构建Component的view时会触发此回调函数。

    示例:

    1. @Override
    2. protected TextView initComponentHostView(@NonNull Context context) {
    3. TextView textView = new TextView(context);
    4. textView.setTextSize(20);
    5. textView.setTextColor(Color.BLACK);
    6. return textView;
    7. }
  • Component 对应的设置属性的方法必须添加注解 @WXComponentProp(name=value(value is attr or style of dsl))

    示例:

    1. @WXComponentProp(name = "tel")
    2. public void setTel(String telNumber) {
    3. getHostView().setText("tel: " + telNumber);
    4. }
  • Weex sdk 通过反射调用对应的方法,所以 Component 对应的属性方法必须是 public,并且不能被混淆。请在混淆文件中添加代码

    1. -keep public class * extends com.taobao.weex.ui.component.WXComponent{*;}
  • Component 扩展的方法可以使用 int, double, float, String, Map, List 类型的参数

  • Component定义组件方法.

    示例:

  • 在组件中如下声明一个组件方法

    1. @JSMethod
    2. public void clearTel() {
    3. getHostView().setText("");
    4. }
  • 注册组之后,你可以在weex 文件中调用

    1. <template>
    2. <div>
    3. <myText ref="telText" tel="12305" style="width:200;height:100" @onTel="onTel" @click="myTextClick"></myText>
    4. </div>
    5. </template>
    6. <script>
    7. export default {
    8. methods: {
    9. myTextClick(e) {
    10. this.$refs.telText.clearTel();
    11. }
    12. }
    13. }
    14. </script>

3.注册TestComponent组件

由于uni小程序运行在独立子进程中。内存与宿主不共享。所以宿主进程注册了TestComponent,在uni小程序是无法使用的。 Android创建子进程时会主动再次初始化Application!所以uni小程序注册TestComponent必须在Application中的onCreate初始化或注册。

Tips

  • 注册TestModule之前记得配置宿主的build.gradle导入的Module模块.
  • 以下示例代码写在宿主的Application中。

示例:

  1. public class App extends Application {
  2. @Override
  3. public void onCreate() {
  4. try {
  5. WXSDKEngine.registerComponent("myText", TestText.class);
  6. } catch (WXException e) {
  7. e.printStackTrace();
  8. }
  9. super.onCreate();
  10. }
  11. }

到此,我们已经完成了一个简单的 component 扩展

4. 在uni小程序代码中使用组件

注意:扩展的 component 只能在 nvue 文件中使用

示例:

  1. <template>
  2. <div>
  3. <myText tel="12305" style="width:200;height:100" @onTel="onTel"></myText>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. data() {
  9. return {
  10. }
  11. },
  12. onLoad() {
  13. },
  14. methods: {
  15. onTel: (e)=> {
  16. console.log("onTel="+e.detail.tel);
  17. }
  18. }
  19. }
  20. </script>

component 自定义发送事件

向JS环境发送一些事件,比如click事件

  1. void fireEvent(elementRef,type)
  2. void fireEvent(elementRef,type, data)
  3. void fireEvent(elementRef,type,data,domChanges)
  • elementRef(String):产生事件的组件id
  • type(String): 事件名称,weex默认事件名称格式为”onXXX”,比如OnPullDown
  • data(Map): 需要发送的一些额外数据,比如click时,view大小,点击坐标等等。
  • domChanges(Map): 目标组件的属性和样式发生的修改内容

示例:

通过 @事件名=”方法名” 添加事件,如下添加onTel事件

  1. //原生触发fireEvent 自定义事件onTel
  2. Map<String, Object> params = new HashMap<>();
  3. Map<String, Object> number = new HashMap<>();
  4. number.put("tel", telNumber);
  5. //目前uni限制 参数需要放入到"detail"中 否则会被清理
  6. params.put("detail", number);
  7. fireEvent("onTel", params);
  1. //标签注册接收onTel事件
  2. <myText tel="12305" style="width:200;height:100" @onTel="onTel"></myText>
  3. //事件回调
  4. methods: {
  5. onTel: (e)=> {
  6. console.log("onTel="+e.detail.tel);
  7. }
  8. }

注意

执行自定义事件fireEvent时params的数据资源都要放入到”detail”中。如果没有将你得返回的数据放入”detail”中将可能丢失。请注意!!!

JSCallback结果回调

JS调用时,有的场景需要返回一些数据,比如以下例子,返回x、y坐标

  1. void invoke(Object data);
  2. void invokeAndKeepAlive(Object data);
  • invoke调用javascript回调方法,此方法将在调用后被销毁。
  • invokeAndKeepAlive 调用javascript回调方法并保持回调活动以备以后使用。

示例:

  1. @JSMethod(uiThread = true)
  2. public void testAsyncFunc(JSONObject options, JSCallback callback) {
  3. Log.e(TAG, "testAsyncFunc--"+options);
  4. if(callback != null) {
  5. JSONObject data = new JSONObject();
  6. data.put("code", "success");
  7. callback.invoke(data);
  8. }
  9. }

注意

执行自定义事件fireEvent时params的数据资源都要放入到”detail”中。如果没有将你得返回的数据放入”detail”中将可能丢失。请注意!!!

Android 扩展开发小提示

查看Android原生日志

小程序运行在独立子进程。所以想要看小程序的日志需要将进程切换到io.dcloud.unimp进程查看log!

查看小程序 console日志

修改项目中assets/data/dcloud_control.xml 内部信息。将syncDebug改为true,开启调试模式。 注意正式版需要改为false!!! 修改后查看io.dcloud.unimp进程查看log。TAG为console

在WXModule、WXComponent中跳转原生页面

获取WXSDKInstance对象。该对象中可以获取到上下文。

示例

  1. @JSMethod (uiThread = true)
  2. public void gotoNativePage(){
  3. if(mWXSDKInstance != null) {
  4. Intent intent = new Intent(mWXSDKInstance.getContext(), NativePageActivity.class);
  5. mWXSDKInstance.getContext().startActivity(intent);
  6. }
  7. }

发现错误?想参与编辑?在 GitHub 上编辑此页面!