一、背景
微信小程序倒退的越来越快,目前小程序甚至取代了大部分 App 的生态位,公司的坑位不增反降,只能让原生利用开发兼顾或换岗进行小程序的开发。
以我的理论状况来讲,公司利用采纳的 Flutter 框架,同样的性能不可避免的就会存在 Flutter 利用开发和微信小程序开发兼顾的状况,这种反复造轮子的工作十分低效。
为什么会呈现这种状况呢?随着 2019 年 5 月 Google I/O 上 Flutter 1.5.4 的公布,宣示着 Flutter 真正开始进入全终端时代,意味着只须要写一份代码,不须要任何额定的修改改,就能够运行在 iOS、Android、Web、PC 上。Flutter 正在革命性的扭转挪动开发的生态系统,从面向各个终端的开发,转向面向框架开发,不仅会扭转开发者的开发方式,也有越来越多的公司开始关注应用 Flutter。
Flutter 作为一个跨平台的框架,其开发技术栈交融了 Native 和前端的技术,不仅波及到了 Native(Android、iOS )的开发常识,又汲取了很多前端(例如 React)的技术理念和框架,并且在此基础上又有晋升,造成 Flutter 本人独特的技术思维。
但目前来讲,Flutter 并不反对小程序,Flutter for Web 尽管最初也会生成 JS 代码,然而 Flutter 生成的 JS 和 CSS 都是不能批改的。而在 Flutter 中也没方法通过 Dart 间接调用小程序的接口,所以现阶段用 Flutter 开发小程序不是太好的抉择。
二、一些解决思路
事实上,随着小程序这种轻量级终端的呈现,公司和业务也不得不向着互联网巨头的流量抬头,同时小程序的逐步风靡,也使得用户下载 App 的习惯产生了变动。不论购物、订餐还是办事,人们都会首先查找“关上即用,即用即走”的小程序,省去了下载 App 的繁琐流程。
当然也晓得很多开发者对于小程序是有十分多意见的,App 也不会说死就死,毕竟 App 绝对于小程序来讲,还是有很多劣势。所以 App 和小程序开发都共存的状况下,如何解决效率问题?是否让过往开发的小程序间接运行在 Flutter 开发的利用中呢?同样一个性能业务仅需一次小程序开发,即可实现在除了微信端的其它 App 中也运行起来。
在 Google 找相干的解决方案和材料的时候,发现国外简直没有这种计划,国内倒是有厂商在做这块,想想也的确合乎情理。基于公司 Flutter 框架的根底现实情况下,名为 FinClip 小程序容器技术的产品是可能反对除原生 iOS、Android 之外的 Flutter 和 React Native ,于是大略测试了下这个产品。
三、FinClip实操
原理其实挺简略的,FinClip 提供了小程序 SDK 给 Flutter 利用进行集成,这样以来 App 即领有了一套可运行小程序业务代码的宿主环境,原理示意图如下。
3.1 获取凭据
集成 SDK 须要在FinClip 平台中创立利用并绑定小程序,取得每个利用专属的 SDK KEY 及 SDK SECRET ,随后能够在集成 SDK 时填写对应的参数。关上小程序时 SDK 会主动初始化,并校验 SDK KEY、SDK SECRET 与 BundleID (Application ID) 是否正确。
3.2 集成插件
首先,关上Flutter我的项目,而后在我的项目的pubspec.yaml 文件中增加依赖。
mop: latest.version
依赖阐明参考:https://pub-web.flutter-io.cn/packages/mop
如果电脑是 mac M1 芯片,还须要在 iOS 文件夹的 Podfile 文件减少以下 3 行代码:
config.build settings ['ENABLE BITCODE'] = 'NO'config.build settings ['IPHONEOS DEPLOYMENT TARGET'] = 19.0'config.build settings ['EXCLUDED ARCHS (sdk=iphonesimulator*]'] = 'arm64 1386'
依赖示例如下:
3.3 Flutter API
在集成mop插件后,应用 SDK 提供的 API 之前必须要初始化 SDK 。上面我列举官网的一些必要的 API ,更具体的也能够查阅官网文档。
1,初始化sdk接口
在应用sdk提供的api之前必须要初始化sdk,初始化sdk的接口为:
/// /// /// initialize mop miniprogram engine. /// 初始化小程序 /// [sdkkey] is required. it can be getted from api.finclip.com /// [secret] is required. it can be getted from api.finclip.com /// [apiServer] is optional. the mop server address. default is https://mp.finogeek.com /// [apiPrefix] is optional. the mop server prefix. default is /api/v1/mop /// [cryptType] is optional. cryptType, should be MD5/SM /// [disablePermission] is optional. /// [encryptServerData] 是否对服务器数据进行加密,须要服务器反对 /// [userId] 用户id /// [finStoreConfigs] 多服务配置 /// [uiConfig] UI配置 /// [debug] 设置debug模式,影响调试和日志 /// [customWebViewUserAgent] 设置自定义webview ua /// [appletIntervalUpdateLimit] 设置小程序批量更新周期 /// [maxRunningApplet] 设置最大同时运行小程序个数 /// Future<Map> initialize( String sdkkey, String secret, { String? apiServer, String? apiPrefix, String? cryptType, bool encryptServerData = false, bool disablePermission = false, String? userId, bool debug = false, bool bindAppletWithMainProcess = false, List<FinStoreConfig>? finStoreConfigs, UIConfig? uiConfig, String? customWebViewUserAgent, int? appletIntervalUpdateLimit, int? maxRunningApplet, })
应用示例:
final res = await Mop.instance.initialize( '22LyZEib0gLTQdU3MUauARlLry7JL/2fRpscC9kpGZQA', '1c11d7252c53e0b6', apiServer: 'https://api.finclip.com', apiPrefix: '/api/v1/mop');
2,关上小程序
/// open the miniprogram [appId] from the mop server. /// 关上小程序 /// [appId] is required. /// [path] is miniprogram open path. example /pages/index/index /// [query] is miniprogram query parameters. example key1=value1&key2=value2 /// [sequence] is miniprogram sequence. example 0,1.2.3,4,5... /// [apiServer] is optional. the mop server address. default is https://mp.finogeek.com /// [apiPrefix] is optional. the mop server prefix. default is /api/v1/mop /// [fingerprint] is optional. the mop sdk fingerprint. is nullable /// [cryptType] is optional. cryptType, should be MD5/SM Future<Map> openApplet( final String appId, { final String? path, final String? query, final int? sequence, final String? apiServer, final String? scene, })
3,获取小程序信息
以后小程序信息,包含的字段有appId、name、icon、description、version、thumbnail等。
/// /// get current using applet /// 获取以后正在应用的小程序信息 /// {appId,name,icon,description,version,thumbnail} /// /// Future<Map<String, dynamic>> currentApplet()
4,敞开小程序
/// /// close all running applets /// 敞开以后关上的所有小程序 /// Future closeAllApplets()
5,清理小程序
革除缓存的小程序,当再次关上时,会从新下载小程序。
/// /// clear applets cache /// 革除缓存的小程序 /// Future clearApplets()
3.4 官网示例
上面是官网提供的一段示例代码。
import 'package:flutter/material.dart';import 'dart:async';import 'dart:io';import 'package:mop/mop.dart';void main() => runApp(MyApp());class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState();}class _MyAppState extends State<MyApp> { @override void initState() { super.initState(); init(); } // Platform messages are asynchronous, so we initialize in an async method. Future<void> init() async { if (Platform.isiOS) { //com.finogeeks.mopExample final res = await Mop.instance.initialize( '22LyZEib0gLTQdU3MUauARlLry7JL/2fRpscC9kpGZQA', '1c11d7252c53e0b6', apiServer: 'https://api.finclip.com', apiPrefix: '/api/v1/mop'); print(res); } else if (Platform.isAndroid) { //com.finogeeks.mopexample final res = await Mop.instance.initialize( '22LyZEib0gLTQdU3MUauARjmmp6QmYgjGb3uHueys1oA', '98c49f97a031b555', apiServer: 'https://api.finclip.com', apiPrefix: '/api/v1/mop'); print(res); } if (!mounted) return; } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('凡泰极客小程序 Flutter 插件'), ), body: Center( child: Container( padding: EdgeInsets.only( top: 20, ), child: Column( children: <Widget>[ Container( decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5)), gradient: LinearGradient( colors: const [Color(0xFF12767e), Color(0xFF0dabb8)], stops: const [0.0, 1.0], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: FlatButton( onPressed: () { Mop.instance.openApplet('5e3c147a188211000141e9b1'); }, child: Text( '关上示例小程序', style: TextStyle(color: Colors.white), ), ), ), SizedBox(height: 30), Container( decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5)), gradient: LinearGradient( colors: const [Color(0xFF12767e), Color(0xFF0dabb8)], stops: const [0.0, 1.0], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: FlatButton( onPressed: () { Mop.instance.openApplet('5e4d123647edd60001055df1',sequence: 1); }, child: Text( '关上官网小程序', style: TextStyle(color: Colors.white), ), ), ), ], ), ), ), ), ); }}
而后,我装置到真机上测试了一下,体验还不错。
参考文档:https://pub-web.flutter-io.cn/packages/mop