Flutter 集成 uni小程序(UniMPSDK)

Author Avatar
Amos
发表:2022-05-10 22:33:10
修改:2022-05-31 00:31:12

又是一段成为鸽子的日子,今天我们直接来上手一把,简单聊聊如何在 Flutter 中集成并使用小程序。

在国内环境下,小程序盛行,随着功能的庞大,许多业务上也需要进行支持,帮助开发进行抽离(减少宿主 APP 频繁发版、方便形成生态、便于独立进行测试与漏洞修复等),使用者也可随需随用、用完即走。

小程序就是一些功能和场景的 “碎片”,而 APP 本身,就是支撑这些 “碎片” 运行的 “宿主”,虽然不是很喜欢小程序所带来的性能问题以及 “阉割” 版 APP 的感觉,但不可否认小程序在开发和用户的快捷场景上带来的好处。

得益于小程序的快速发展,诞生出非常多相关技术支持的公司,在 pub.dev 上其他开发者以及公司直接提供了集成插件,但为了自己能更灵活地把控程序以及担忧插件持续维护的问题,我这里选择了非常成熟的 uni-app 自己进行集成。

效果

首先我们来看看 Flutter 集成 uni小程序的效果。
源码示例工程(实验室-小程序):https://github.com/AmosHuKe/Mood-Example

实现思路

uni-app 官方文档以及其他教程都是教学如何在原生平台进行集成。
首先我们能够知道 Flutter 和 uni-app 都是属于 UI 框架,运行在原生系统上的。
UI 框架之间没有办法直接通讯,但我们可以利用原生的能力将他们两位打通。
我这里利用的是 Flutter 中 MethodChannel 的能力,它能够异步地让 Flutter 与原生平台之间的方法互相调用。
使用通道在 Flutter 和原生平台之间传递消息,如下图所示:

所以,我们只需要在对应的原生平台(Android、IOS)编写业务需要的 uni-app API 方法,Flutter 再通过 MethodChannel 的通道与原生平台进行通讯即可。

具体集成实现

开发环境

基础环境:

[√] Flutter (Channel stable, 2.10.5, on Microsoft Windows [Version 10.0.22000.556], locale zh-CN)
[√] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.1.3)
[√] Android Studio (version 2020.3)
[√] VS Code (version 1.66.0)

小程序 SDK :

UniMPSDK-Android: 3.4.7.V2.20220425
UniMPSDK-IOS: 暂未集成(实现思路一致)

小程序打包基座:

HBuilderX: 3.4.7(尽量与 UniMPSDK 版本一致)
JAVA 环境: jdk1.7+(最优1.8)
Android API: 最低运行版本 21

Android UniMPSDK 集成

官方原生平台教程:uni小程序SDK
以下为我个人集成流程。

UniMPSDK 目录说明

├── UniMPSDK
│   ├── DEMO              # uni小程序 SDK 集成示例 DEMO
│   └── SDK               # uni小程序 SDK
│   │   ├── assets        # assets 资源文件
│   │   ├── libs          # 所有依赖库
│   │   ├── res           # 资源文件
│   │   ├── src           
│   │   │   └── wxapi     # 微信分享支付需要的 activity
│   │   └── proguard.cfg  # 混淆配置

Libs 依赖库配置

项目位置(没有则自行创建):项目/android/app/libs/
对应 UniMPSDK 位置:UniMPSDK/SDK/libs/

Libs 文件夹依赖库可根据功能需要进行增加或删除,除视频、地图、分享、支付、登录、直播pusher 等 SDK,只集成以下基础模块就可使用:

uniMPSDK-V2-release.aar    # 必须集成
uniapp-v8-release.aar    # 必须集成
android-gif-drawable-release@1.2.23.aar    # 必须集成
base_oaid_sdk.aar    # 必须集成 注意(3.3.8版本的SDK及以下版本请集成oaid_sdk_1.0.25.aar)
sqlite-release.aar
messaging-release.aar
iBeacon-release.aar
fingerprint-release.aar
contacts-release.aar
Bluetooth-release.aar

build.gradle 配置

项目位置:项目/android/app/build.gradle

以下为基础配置,具体可参考 UniMPSDK 中 UniMPSDK/DEMO/app/build.gradle 文件。

android {
    defaultConfig {
        applicationId "宿主项目包名 xxx.xxx.xxxxx"
        minSdkVersion 21 // 最低支持21
        targetSdkVersion 30 // 最优26 2.8.11开始最高支持30
        ndk {
            abiFilters 'x86','x86_64','armeabi-v7a','arm64-v8a' // 不支持armeabi
        }
    }

    buildTypes {
        release {
            minifyEnabled true
            // 混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'
        }
    }

    // 此处配置必须添加 否则无法正确运行
    aaptOptions {
        additionalParameters '--auto-add-overlay'
        // noCompress 'foo', 'bar'
        ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"
    }
}

// 导入 arr 需要的配置
repositories {
    flatDir {
        dirs 'libs'
    }
}

dependencies {
    // libs UniMPSDK
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation fileTree(include: ['*.aar'], dir: 'libs')
    // 必须添加的依赖
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.alibaba:fastjson:1.1.46.android'
    implementation 'com.facebook.fresco:fresco:1.13.0'
    implementation 'com.facebook.fresco:animated-gif:1.13.0'
    implementation 'com.github.bumptech.glide:glide:4.9.0'
}

assets 基础资源配置

1、将 UniMPSDK/SDK/assets 内的所有文件按目录放入 项目/android/app/src/main/assets 中(没有目录自行创建)。
2、创建 uni小程序资源文件夹:在 项目/android/app/src/main/assets/ 下创建 apps 文件夹 用于放置 uni小程序打包发行的程序。

proguard 混淆配置

UniMPSDK/SDK/proguard.cfg 文件放入 项目/android/app/ 中。

打包发行 uni-app 小程序

注意:
仅支持 uni-app 小程序
HBuilderX 一般情况可以向下兼容 UniMPSDK 的版本,但尽量 HBuilderX 和 UniMPSDK 的版本保持一致。

打开 HBuilderX,新建一个示例项目或者自己编写。

在小程序项目的 manifest.json 内获取并使用 uni-app 应用标识(AppID),也是我们之后指定操作小程序的标识。

使用 【发行 => 原生App-本地打包 => 生成本地打包App资源】 生成本地包。

将打包好的内容放入 项目/android/app/src/main/assets/apps/ 内,文件结构必须如下:

├── apps
│   ├── __UNI__xxxxxxx  # 小程序1
│   │   └── www
│   │   │   └── ...     #小程序编码
│   ├── __UNI__xxxxxxx  # 小程序2
│   │   └── www
│   │   │   └── ...     #小程序编码

原生实现 MethodChannel

项目位置:项目/android/app/src/main/kotlin/com/example/moodexample/MainActivity.kt

Android 端需要在 FlutterActivity 的 configureFlutterEngine 方法中获取 FlutterEngine 对象。
接着再创建 MethodChannel 通道实例,最后对通道设置 MethodCallHandler 回调。
根据我们的业务(需要调用 UniMPSDK API 打开指定的 uni小程序 并监听),创建一个名为 UniMP_mini_apps 的通道以及名为 open 的方法帮助我们操作 UniMPSDK 打开小程序。

UniMPSDK API: Android API V2版本参考手册

import io.dcloud.common.adapter.util.Logger
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

import io.dcloud.feature.sdk.DCUniMPSDK;
import io.dcloud.feature.sdk.Interface.IUniMP
import io.dcloud.feature.sdk.DCSDKInitConfig

import io.dcloud.feature.sdk.MenuActionSheetItem
import io.flutter.Log

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        val messenger = flutterEngine.dartExecutor.binaryMessenger
        // Channel 对象
        val channel = MethodChannel(messenger, "UniMP_mini_apps")
        // Channel 设置回调
        channel.setMethodCallHandler { call, res ->
            // 根据方法名,分发不同的处理
            when(call.method) {
                // 打开指定的 UniMP 小程序
                "open" -> {
                    try {
                        // 接收 Flutter 传入的参数
                        val argumentAppID = call.argument<String>("AppID")
                        // 设置右上角胶囊操作菜单
                        val item = MenuActionSheetItem("关于", "about")
                        val sheetItems: MutableList<MenuActionSheetItem> = ArrayList()
                        sheetItems.add(item)
                        // 初始化uniMPSDK
                        val config = DCSDKInitConfig.Builder()
                                .setCapsule(true)
                                .setMenuDefFontSize("16px")
                                .setMenuDefFontColor("#2D2D2D")
                                .setMenuDefFontWeight("normal")
                                .setMenuActionSheetItems(sheetItems)
                                .build()
                        DCUniMPSDK.getInstance().initialize(this, config)

                        // 打开小程序
                        val unimp: IUniMP = DCUniMPSDK.getInstance().openUniMP(context, argumentAppID)
                        // 监听胶囊菜单点击事件
                        DCUniMPSDK.getInstance().setDefMenuButtonClickCallBack { argumentAppID, id ->
                            when (id) {
                                "about" -> {
                                    Logger.e(argumentAppID + "点击了关于")
                                }
                            }
                        }
                        // 监听小程序关闭
                        DCUniMPSDK.getInstance().setUniMPOnCloseCallBack { argumentAppID -> Log.e("unimp", argumentAppID + "被关闭了") }
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }

                else -> {
                    // 如果有未识别的方法名,通知执行失败
                    res.error("error_code", "error_message", null)
                }
            }
        }
    }
}

Flutter 调用

在 Dart 代码中创建一个相同的通道 UniMP_mini_apps,通过 MethodChannel 的 invokeMethod 调用通道的 open 方法,打开并监听指定的小程序。

/// 创建通道与原生沟通
const channel = MethodChannel("UniMP_mini_apps");

Future callNativeMethod(String appID) async {
  try {
    // 通过通道,调用原生代码代码的方法
    final future = await channel.invokeMethod("open", {"AppID": appID});
    // 打印执行的结果
    print(future.toString());
  } on PlatformException catch (e) {
    print(e.toString());
  }
}

/// 传入 uni-app 应用标识(AppID)打开指定的小程序  
callNativeMethod("__UNI__xxxxxxx");

扩展能力

  • 非内置 uni小程序集成方式:应用资源包(.wgt)可以选择从云端获取或共享文件等方式,宿主通过 uni小程序 SDK 的 API 调用 releaseWgtToRunPath 实现释放资源包集成 uni小程序。
  • 扩展原生能力
  • 更多依赖包内置功能模块集成
  • 等等…

都可在此处查阅:uni 小程序 SDK

相关资料

转载请遵循 协议许可
本文所有内容严禁任何形式的盗用
本文作者:Amos Amos
本文链接:https://amoshk.top/2022050801/

评论
✒️ 支持 Markdown 格式
🖼️ 头像与邮箱绑定 Gravatar 服务
📬 邮箱能够收到回复提醒(可能会在垃圾箱内)