MPFlutter搞一个微信小程序

12,584 阅读7分钟

前言

最近使用MPFlutter框架将公司官网做成了一个小程序特爱Lite并发布上线。

首先感谢作者 PonyCui 开源这个框架,让Flutter有更多的可能,仅以此文介绍下MPFlutter框架及开发总结。

官方文档 github

效果先行

自己看着做的,UI略丑轻喷。😂

MPFlutter简介

官网介绍

MPFlutter 是一个跨平台 Flutter 开发框架,可用于各种小程序、H5、原生应用开发。

开发者可以通过 Dart 语言开发 App,一套代码同时运行在以下平台。

  • 微信小程序
  • 百度小程序
  • 字节小程序、飞书小程序
  • Web (HTML5)

MPFlutter 提供了丰富的组件、接口,开发者可以轻松地为应用添加平台扩展。

以上摘自MPFlutter官网简介,详细请查看官方文档

鄙人拙见

以下是鄙人拙见,如有错误欢迎指正。

MPFlutter是阉割版的Flutter:裁剪非必须渲染层打包成Web并通过 kbone框架在小程序上运行的Flutter变种框架。 实际上是让将Futter Web项目运行在小程序上,借用kbone在小程序下搭建一个可运行web的模拟环境 Tencent kbone Github

那么MPFlutter的缺陷也就很明显了

  • 不少Flutter Widget不支持 核心Widget
  • 很多Flutter三方库不能直接使用如果三方库引入了MPFlutter不支持的Widget则无法使用支持的三方库;dart packages是可以直接使用的。如工具类common_utils、日志打印logger等。
  • 不少基础组件都需自行实现如TextButtonTextFieldForm 针对小程序及Web的组件库MPKit

MPFlutter优点也是很明显的。

  • kbone封装好微信小程序百度小程序字节/飞书/头条程序WEB底层部分。开发者只需关注dart代码编写及极小的差异化配置即可
  • 维护部分必要三方库针对小程序的适配 如网络请求diohttp;状态管理GetXBlocProvider等。开发者只需要同Flutter环境下一样的使用方式即可
  • 封装小程序组件API让开发者可调用小程序的组件及API-如 地图用户登录授权定位扫码等功能
  • 扩展方便-如有需要可联系作者扩展到其它小程序平台。不过感觉没有必要😂
  • Flutter技术栈的开发者可丝滑的过渡进行小程序开发

以笔者做完整个项目来看--包括前端图文展示html渲染地图展示地图导航打开其它小程序详情页面;以及后端数据录入产品、案例图文上传新增编辑删除排序等相关功能。MPFlutter是能满足绝大多数小程序应用场景的。商用是没有问题的,大家可放心食用。

配置注意事项

官网有完整详细的 WindowsmacOSLinux三个平台下环境配置配置文档,此处不详细展开。只着重提一下笔者配置过程遇到的容易出错点

  • macOSdart sdk环境变量配置-注意全局环境变量配置并且要区分系统以下摘自flutter.cn
打开或者创建 shell 的 `rc` 文件,
比如,在 Linux 和 macOS Mojave 或 Mojave 之前的系统里,是默认使用 Bash 的,所以需要修改 `$HOME/.bashrc` 文件。 
macOS Catalina 操作系统默认使用 Z Shell,所以需要修改 `$HOME/.zshrc` 文件。
请知晓,如果你使用不同的 shell,文件目录或文件名可能会有所不同。

如图出现 zsh: command not found: dart2js 则为dart sdk未配置好造成需在 .zshrc文件增加 export PATH="$PATH:$path/flutter/bin/cache/dart-sdk/bin" 其中$path改为自己FlutterSDK目录 如笔者的完整路径为export PATH="$PATH:/Users/scta/develop/Flutter/SDK/flutter/bin/cache/dart-sdk/bin"$path/Users/scta/develop/Flutter/SDK 最后执行 source ~/.zshrc 保证变量即刻生效。再执行dart2js --version一切正常。

2022-05-30新增

  • Windows平台下使用要借助工具Windows PowerShell,否则直接在Android Studio Terminal执行./mpflutter packages get会提示异常。打开Windows Power Shell然后 cd 到项目目录下,再执行./mpflutter packages get
异常提示Windows PowerShell执行正常MPFlutter出处

调试注意事项

  • 在开发模式下如需在微信开发者工具中实时预览效果需修改weapp文件夹下的app.js文件。将engine.initWithDebuggerServerAddr设置的ip为本机ip,且真机调试时保证手机和电脑在同一局域网下,端口一定不能修改。
    if (dev) {
      engine.initWithDebuggerServerAddr("192.168.xxx.xx:9898");
    } else {
      engine.initWithCodeBlock(Engine.codeBlockWithFile("./main.dart.js"));
    }
  • 不能同时调试两个项目或者在项目运行或调试时再次点击运行或调试否则会出现端口占用问题

  • 真机调试时微信开发者工具模拟器选择或自定义与真机分辨率一致,避免真机上页面显示异常。

模拟器与真机分辨率不一致如下图

模拟器与真机分辨率一致如下图

功能总结

笔者使用MPFlutter 0.15.4版本开发,以下功能总结亦是基于此版本。截止目前2022-05-27最新版本为0.16.0

白屏问题

笔者是从Android开发过来的,相信做过Android开发的都被启动的黑屏/白屏困扰过。

MPFlutter因为是kbone加载Web故在进入程序或切换新页面会先显示小程序的pages/index/index页面待 Web页面加载出来再渲染到pages/index/index。这个过程有近300-500ms的时间,这段时间pages/index/index没有内容故显示出白屏/黑屏状态。这个是框架(Flutter Web)造成,目前能做的是在pages/index/index做一个loading效果在MPFlutter一侧做同一种loading效果。

首先在index.wxss增加一个loading-bg背景让旋转圆圈居中,再增加一个旋转圆圈loading-circle

.loading-bg{
  position: absolute;
  top: 120;
  left: 0;
  width: 100%;
  height: 100%;
  flex-direction: column;
  align-items: center;
  align-content: center;
  display:flex;
  align-self: center;
  justify-self: center;
  justify-content: center;
}
.loading-circle {
  box-sizing: border-box;
  width: 2.075rem;
  height: 2.075rem;
  display: inline-block;
  border: 0.2rem solid #00000000;
  border-top: 0.2rem solid #2196F3;
  border-radius: 100%;
  /* 动画旋转效果 */
  animation: rotate-360 0.8s infinite linear;
}

@keyframes rotate-360 {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

最后在index.wxml设置即可,其中element为承载Flutter Web的容器

<page-meta><navigation-bar title="{{pageMeta.naviBar.title}}" loading="{{pageMeta.naviBar.loading}}" ></navigation-bar></page-meta>
    <view class="loading">
          <view class="loading-css"/>
     </view>
<element wx:if="{{pageId}}" class="miniprogram-root" data-private-node-id="e-body" data-private-page-id="{{pageId}}" >
</element>

可以看到先是一个小程序端的蓝色loading再是一个MPFlutter端的绿色loading--故意在MPFlutter端每日一换的彩虹主题色(周四绿色😂)。

差强人意,当然这是简单做一个过渡让人不要以为程序卡住。开发者可根据实际情况做其它更精美的loading效果。这里权当抛砖引玉了。

DarkMode

Flutter及微信小程序是支持DarkMode的,遗憾的是笔者开发时MPFlutter还不支持的。根据最新消息新版本0.16.0已支持。官方文档-深色模式适配指南

这里介绍下自己实现流程,仅供参考。

首先:根据 微信文档DarkMode 部分进行 app.json配置。此处不做赘余

其次:通过wx.onThemeChange监听系统主题变化。此处需通过universal_miniprogram_api库可进行相应监听。接收到主题变化后再通过UniversalMiniProgramApi.uni.getSystemInfoSync()获取系统属性中的theme 通过返回值判断主题。

最后:通过状态管理库GetXBlocProvider进行相应主题变更即可。

效果概览动态切换主题

2022-05-28升级了0.16.0版本尝试了下。MPFlutter框架层可获取系统当前主题。但是没有对应监听---即打开小程序情况下更改系统主题,MPFlutter是无法实时获取当前主题的,故根据自己需求使用。

打开其它小程序指定页面

这块本身是微信API-wx.navigateToMiniProgram支持的,且MPFlutter也有对应的uni.navigateToMiniProgram支持,关键需要找到小程序appId及页面路径path即可。 此处分享一下查找流程。 特爱Lite小程序有个招聘岗位跳转智联招聘小程序职位详情功能。故以此为例。

appId很好找-直接点击胶囊按钮进入小程序详情页,点击更多资料AppID赫然在列。

比较难找的是path。后台录入的是PC端的网页,一般这种网页理论上是有手机端的。然后试着通过微信打开。果不其然弹框直接提示打开小程序查看。这不是巧了么这不是。

然后右上角复制链接得到一个mobile网页https://m.zhaopin.com/jobs/XXX.htm,然后再通过PC端打开然后点击打开小程序查看得到一个如下页面

然后右键显示网页源代码拖动到script部分。关键代码如下

window.data = {
          head_img_url: 'http://wx.qlogo.cn/mmhead/Q3auHgzwzM4fuY86JHvlu5FNDw5JeJybkY6icSdcU3eEUav8iacOJu1g/132',
          nickname: '智联招聘 靠谱工作视频见',
          url_scheme: 'weixin://dl/business/?t=nGwBOXZzPKf',
          user_name: 'gh_8a245d4e3002',
          path: 'pages/position/detail/detail',
          query: 'utm_source=mJdDetailsMore&number=CC458880730J40286792416',
        }

path是不是呼之欲出。还可以看到query参数有个number应该是职位id类似的东西刚好是网页https://m.zhaopin.com/jobs/XXX.htm XXX部分使用字符串切割获取即可。

最终的 pathpages/position/detail/detail?number=$number至此即可跳转智联招聘小程序职位详情页面。

打开其它小程序详情页面

跳转其它小程序如法炮制。关键点得找到path这个一般是不会对外公开的。只有找下对应网站的mobile版有没有类似跳转小程序功能可通过查看源码方式进行获取。(如Boss直聘笔者就没有找到跳转对应岗位详情的网页,只找到跳转岗位发布人详情页面path,有知道跳转岗位详情的方法万望不吝赐教,感谢!!!)

小程序分享并打开目标页面

注意:该方式适用于0.16.0之前版本。0.16.0开始分享功能实现更简单,根据自己版本做选择。

MPScaffold提供onWechatMiniProgramShareAppMessage用于传递分享参数用于点击打开小程序后获取对应参数。

比较重要的是在回调参数返回path用于告诉微信需要打开小程序的页面,对MPFlutter路径固定为/pages/index/index 固定参数route用于告诉MPFluter打开页面的路由。其它参数则依次拼接其后。如Web网页参数拼接模式/pages/index/index?route=$routeName&keyA=valueA&keyB=valueB最后进入$routeName页面后可通过ModalRoute.of(context)?.settings.arguments获取到map对象

{
    "route":"$routeName",
    "nextRoute":"/newsDetailPage",
    "keyA":"valueA",
    "keyB":"valueB",
    "$viewportWidth":320,
    "$viewportHeight":568
}

其中route即为目标路由与Flutter中调用Navigator.of(context).pushNamed一样效果。进入目标路由则可通过其它参数进行相关操作。如分享资讯详情页/pages/index/index?route=/infoDetail&id=xyz,点击即可直达对应的详情页面。详情页面拿到id请求网络渲染html即可。

分享给好友好友点开

gif所示笔者做的操作是先进入主页面再二次跳转到目标页面。这里自己业务场景处理即可。

0.16.0版本升级了分享功能。具体可参考官方文档-分享小程序页面至微信,热乎的。

2022-05-28升级了0.16.0版本。果然参数传递要简单很多。

MPScaffold(
  name: 'Template',
  onWechatMiniProgramShareAppMessage: (request) async {
    return MPWechatMiniProgramShareInfo(
      title: '分享标题',
      imageUrl: 'http://abc.com/123.png', // 封面图
      routeName: '/',
      routeParams: {
        'id':'xx',
      },
    );
  },
  //body: ...
)
  • title 分享标题(默认MPScaffold.name)
  • imageUrl分享封面图(默认当前分享页面截图)
  • routeName 指定点击分享后打开路由(默认根布局)
  • routeParams 指定传递到路由的参数

渲染html

特爱Lite小程序有个资讯中心模块,用于展示后台编辑的html代码。MPFlutter维护了一套simple_html_css库用于渲染html代码。不过天不遂人愿,并不能渲染出来我们后台的html。起初以为是MPFlutter的锅,结果我在Flutter环境下使用原版simple_html_css也是渲染不出来的。然后我开始自我怀疑了:难道是我后台生成的html问题?,但是转念一想web端渲染不也是正常的么。于是我在Flutter环境下用flutter_html结果是完美解析的。那么真相只有一个姿势不对😀

于是参考flutter_html源码借助csslibhtml库将后台html解析成Element并根据标签转义成Flutter端的组件即可。

好在咱们后台就文本下划线图片超链接等为数不多的效果。解析起来工作量也还行,还原度还是不错。

web端效果Flutter App效果MPFlutter小程序效果

Windows平台效果微调

2022-05-28Windows平台下顶部AppBar去掉,因自定义AppBarWindows下无法去掉。--不知道为啥?(有知道内幕的麻烦扫一下知识盲区😂)

于是在Windows下隐藏掉自定义的AppBar并且将搜索按钮放在floatBody处。其它平台不变。

改变前
改变后

治好了我多年的强迫症😀

结语

5月 Flutter3.0正式发布,至此全平台进入stable状态。想搞得都可以搞起来了。

MPFlutterFlutter扩展到小程序让我们看到了Flutter的更多可能,尽管还有诸多不足。但是瑕不掩瑜还是值得大家学习尝试一下的。商用亦可

再次感谢MPFlutter作者 PonyCui 的开源精神。

另外:有什么使用MPFlutter有什么问题,可以直接GitHubissue,作者是住Github的反馈很及时。给作者点赞👍👍👍

image.png

其中 MPFlutter框架层支持DarkMode及分享参数逻辑优化已在0.16.0支持。