diff --git a/docs/plugin/_sidebar.md b/docs/plugin/_sidebar.md index 1e3f7369479d7cdc817076a3c8ed5241a5a637dc..648e49d0083fa89ce2faccb035b4d6859dae686f 100644 --- a/docs/plugin/_sidebar.md +++ b/docs/plugin/_sidebar.md @@ -8,4 +8,5 @@ * [Android平台uts开发指南](uts-for-android.md) * [iOS平台uts开发指南](uts-for-ios.md) * [使用CocoaPods依赖](uts-ios-cocoapods.md) + * [原生插件转uts页面](native-covert-uts.md) * [插件作者专区](https://uniapp.dcloud.net.cn/plugin/publish.html) diff --git a/docs/plugin/native-covert-uts.md b/docs/plugin/native-covert-uts.md new file mode 100644 index 0000000000000000000000000000000000000000..efe83b7f5c15b9405f6ef5a15ef1252bfbaf2da8 --- /dev/null +++ b/docs/plugin/native-covert-uts.md @@ -0,0 +1,430 @@ +## 为什么要把原生插件迁移为UTS插件 + + ++ 更大的使用范围 + +原生插件仅支持 uni-app 平台,UTS插件则同时支持 uni-app & uni-app x 双平台 + ++ 更好的性能 + +对于 uni-app x 项目: UTS插件不再通过 jsbridge 传递序列化数据的方式进行通讯,而是直接在原生语言形态中调用,可以让插件具备原生应用的性能 + ++ 更好的开发体验 + +插件开发和业务代码可以通过 HBuilder X 一站式完成,调试插件再也不需要切换IDE + ++ 更丰富的API + +UTS插件 内置了更多的API,还提供了更加友好的调用系统API的方式,插件能力更加丰富 + + + +关于原生插件和UTS插件的更多差异,可以查看 +[文档](https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin.html#uts%E6%8F%92%E4%BB%B6%E4%B8%8Euni%E5%8E%9F%E7%94%9F%E8%AF%AD%E8%A8%80%E6%8F%92%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) + +UTS插件是对原生插件的一次全面升级,可以给插件开发者/使用者带来诸多好处。 + +本文将会以 [原生插件工程示例](https://nativesupport.dcloud.net.cn/NativePlugin/course/android.html)为例进行演示,帮助开发者实现原生插件到UTS插件的平滑迁移。 + +## module 插件迁移思路 + +常规的`UTS插件`开发过程是这样的: + ++ 1 开发插件:开发者在HBuilder X 具体的项目中 编写UTS语言插件 + ++ 2 生成原生代码:UTS编译器 根据项目类别,将UTS语言编译成 符合 `uni-app` / `uni-app x` 平台规范的 kotlin 源码 + ++ 3 使用插件: 开发者在 业务代码中使用 UTS插件中导出的 函数/类/组件 + ++ 4 发布或运行应用:HBuilder X 提交打包,将生成的 业务代码和插件代码 编译整合 + +```mermaid +flowchart TD + A[编写UTS插件] -->|编译|B{编译器:判断项目类型} + B --> C[uni-app] + B --> D[uni-app x] + C --> |自动编译|E[kotlin源码] + D --> |自动编译|E[kotlin源码] + E --> |编译|F[字节码产出物] +``` + + +我们将`原生插件`转换为`UTS插件`的过程,实际是手动完成 步骤1 和 步骤2 并将产出物打包为AAR,作为外挂,添加进入UTS插件的过程 + +流程如下: + +```mermaid +flowchart TD + A[搭建原生开发环境] --> C{开发者:选择项目类型} + C --> |手动编写|D[uni-app] + C --> |手动编写|E[uni-app x] + D --> |gradle打包|F[AAR] + E --> |gradle打包|F[AAR] + G[新建UTS插件] --> H[编写必要的UTS调用代码] + H --> |编译|I[kotlin源码] + F --> J[字节码产出物] + I --> J[字节码产出物] +``` + + + +在已有原生插件的情况,我们需要做的事可以概述为: + +删除 `uniModule`等规范约束,使其退化为原始的最基础的java class。再打包为 aar,供UTS插件代理调用 + + +具体为下列实施步骤: + +|序号|步骤|简介| +|:--|:--|:---| +|1|离线打包环境搭建|不同项目类型的依赖库添加| +|2|打包并集成AAR|将插件打包为 AAR 产出物形式,并添加到UTS插件中,供业务代码使用| +|3|编写调用代码|编写必要的UTS代码,调用AAR中的实现,注意:生命周期相关的代码也在这里手动实现| + + +## module 插件迁移实践 + +#### 离线打包环境搭建 + + +前置环境: + ++ java版本:17 + ++ gradle 版本:8.2 + ++ compileSdk 33 + ++ kotlin:1.9.10 + + + +如果是 `uni-app`环境,添加下面的依赖 + +```gradle +/** + * uni-app 运行时能力 + */ +compileOnly fileTree(dir: '../app/libs', include: ['utsplugin-release.aar']) +/** + * 添加UTS语言能力 + */ +compileOnly fileTree(dir: '../app/libs', include: ['utsplugin-release.aar']) +``` + +![module_gradle_1.png](https://web-ext-storage.dcloud.net.cn/doc/uts/convert_android/module_gradle_1.png) + + +如果是 `uni-app x`环境,添加下面的依赖 + +```gradle +/** + * uni-app x运行时能力 + */ +compileOnly fileTree(dir: '../app/libs', include: ['app-runtime-release.aar']) +/** + * 添加UTS语言能力 + */ +compileOnly fileTree(dir: '../app/libs', include: ['uts-runtime-release.aar']) +``` + + +#### 改造操作 + +以`原生插件示例`为例,具体做了下面的改造工作: + ++ 1 移除 uniModule @UniJSMethod 注解 + ++ 2 UniJSCallback 平替为 UTSCallback. invokeAndKeepAlive/invoke 统一替换为 invoke + ++ 3 系统声明周期API 平替为 UTSAndroid的api + +比如: super.onActivityResult 移除,对应的功能实现,迁移到 UTS 插件中 + ++ 4 获取 Activity/Application 上下文的代码 替换为 UTSAndroid.INSTANCE.getUniActivity() + + + +下面是修改完成后的 TestModule + +```java +package io.dcloud.uniplugin; + +import android.content.Intent; +import android.util.Log; +import com.alibaba.fastjson.JSONObject; +import io.dcloud.uts.UTSAndroid; +import io.dcloud.uts.UTSCallback; + +public class TestModule { + + String TAG = "TestModule"; + public static int REQUEST_CODE = 1000; + + public void testAsyncFunc(JSONObject options, UTSCallback callback) { + Log.e(TAG, "testAsyncFunc--"+options); + if(callback != null) { + JSONObject data = new JSONObject(); + data.put("code", "success"); + callback.invoke(data); + } + } + + public JSONObject testSyncFunc(){ + JSONObject data = new JSONObject(); + data.put("code", "success"); + return data; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if(requestCode == REQUEST_CODE && data.hasExtra("respond")) { + Log.e("TestModule", "原生页面返回----"+data.getStringExtra("respond")); + } + } + + public void gotoNativePage(){ + if(UTSAndroid.INSTANCE.getUniActivity() != null) { + Intent intent = new Intent(UTSAndroid.INSTANCE.getUniActivity(), NativePageActivity.class); + UTSAndroid.INSTANCE.getUniActivity().startActivityForResult(intent, REQUEST_CODE); + } + } +} + +``` + + + +将 uni-module 进行打包,得到 `uniplugin_module-release.aar` + +![module_aar_1](https://web-ext-storage.dcloud.net.cn/doc/uts/convert_android/module_aar_1.png) + +在HBuilder X 中新建一个插件,充当代理作用,这里我们起名为`uts-module`。 现在的目录结构是这样的 + +![module_structure_1](https://web-ext-storage.dcloud.net.cn/doc/uts/convert_android/module_structure_1.png) + +编写必要的调用代码,另外插件生命周期监听也是在这里完成。这里是编写完毕的index.uts代码 + +```ts +import TestModule from 'io.dcloud.uniplugin.TestModule' +import JSONObject from 'com.alibaba.fastjson.JSONObject' +import Intent from 'android.content.Intent' + +/** + * 我们封装进AAR 里面的java 对象,通过操作它,我们可以调用原生实现的代码 + */ +let testModule = TestModule() +/** + * UTS是强类型语言,我们在这里声明了一个函数,用来承接系统的onActivityResult回调 + */ +let resultCallback:((requestCode : Int, resultCode : Int, data ?: Intent)=>void)|null = null + +/** + * 对外暴露 uts_testAsyncFunc方法,实现直接调用AAR中的实现 + */ +export function uts_testAsyncFunc(options:UTSJSONObject,callback: (ret:Any) => void) { + testModule.testAsyncFunc(options.toJSONObject() as JSONObject,new UTSCallback(callback)) +} +/** + * 对外暴露uts_testSyncFunc方法,实现直接调用AAR中的实现 + */ +export function uts_testSyncFunc():UTSJSONObject { + let syncRet = testModule.testSyncFunc() + return new UTSJSONObject(syncRet); +} +/** + * 对外暴露uts_gotoNativePage方法 + */ +export function uts_gotoNativePage(){ + + /** + * 这里对onActivityResult 事件进行了监听 + */ + let testModule = TestModule() + resultCallback = (requestCode : Int, resultCode : Int, data ?: Intent) => { + let eventName = "onAppActivityResult - requestCode:" + requestCode + " -resultCode:" + resultCode + " -data:" + JSON.stringify(data); + console.log(eventName); + UTSAndroid.offAppActivityResult(resultCallback) + testModule.onActivityResult(requestCode,resultCode,data) + } + UTSAndroid.onAppActivityResult(resultCallback!); + + testModule.gotoNativePage() +} + +``` + + +在ext-module.vue 中使用插件: + +```vue + + + +``` + +运行测试功能正常, + +至此我们完成了 Android原生插件中module 到 UTS插件的迁移工作 + +## component 迁移思路 + +component 插件的迁移思路和module插件不同。 + +因为component存在更多的规范约束,我们只能选择将其彻底翻译为[UTS页面组件](https://doc.dcloud.net.cn/uni-app-x/plugin/uts-component.html) + + +## component 迁移实践 + +以 `uniplugin_component` 为例: + +新建一个UTS页面组件,名称为:`uts-test-text` + +![component_1](https://web-ext-storage.dcloud.net.cn/doc/uts/convert_android/component_1.png) + ++ 修改 name字段为 `uts-test-text` + ++ `emit` 添加 `ontel` 事件,特别注意: 事件名称必须要修改为全小写 + ++ 声明 `tel` 属性,并在 `watch` 方法中监听属性变化 + ++ 声明并对外暴露 `clearTel`方法 + ++ 迁移 布局创建文件至 `NVLoad` 方法 + +这里修改后的 `index.uvue` + +```vue + + + + + +``` + +在nvue中使用该组件 + +```vue + + + + + +``` + + + +至此,我们完成了 `component` 到UTS页面组件的迁移工作 \ No newline at end of file