Flutter自定义库之一:从自定义webview库经历,了解Flutter开发遇到的一些列问题

东方盛慧科技大约 4 分钟flutterflutter

Flutter自定义库之一:从自定义webview库经历,了解Flutter开发遇到的一些列问题

从webview升级的经历了解开发flutter应用所要面临的问题,及相关问题和痛点的解决

公司原生App(安卓、iOS),有大量的H5页面集成,课程介绍、购买,意见反馈,订单,社区等功能都是由h5开发,然后由原生webview去加载,中间涉及h5和原生的交互。

一、为了满足公司的业务需求,因此

flutter_webview需要支持的功能有:

  1. 首次初始化需要自定义cookie和UA,(cookie是用于判断是否登录,ua是用于识别公司自定义的app信息,比如appid,操作系统等)
  2. 为了尽可能保持两端统一,js交互实现,需要以flutter层为主(公司之前js调用原生,android和ios采用了不同的处理方式,再开发flutter需要保持统一)
  3. 可以拦截请求的url并进行自定义处理(h5会启动支付宝等三方应用还有判断是否h5登录页面,需要拦截处理)
  4. 自定义的时候不仅需要同事间可以协作开发,还需要能够及时跟官方代码保持同步(git解决)

二、自定义flutter_webview开发经历:

  1. 自定义1.0版本,开发最初flutter_webview为2.1.3,官方flutter_webview不能满足第一个痛点需求,首次进入的加载地址无法携带自定义cookie,于是下载代码到本地git服务器,并进行修改,项目中采用直接git依赖的方式,彻底与官方代码脱钩,埋下了隐患。
  2. 自定义2.0版本,协调h5,js调用原生代码保持统一,这样flutter代码才能保持统一,中间也是踩了不少坑,h5也涉及到各个业务块,这块儿代码并不是统一的(支付、意见反馈、其它业务块儿),都要协调修改,沟通发版成本也比较高。
  3. 自定义3.0版本,采用官方flutter_webview最新代码3.0.0,采用搭建私服+git版本控制的方式,解决了既能协作开发,又能及时合并官方代码。
  4. 自定义3.0+版本,为了接入支付,需要拦截url地址,修改原生代码,android由于启动三方app需要有上下文context, 所以拦截位置和ios处理位置略有不同。

三、中间衍生的其它问题

  1. 代码无法同步问题处理
  • 1.1. 拉取官方最新代码,使用git的sparse-checkout配置做目录控制,并添加公司源,这样可以合并官方最新代码到公司git源上,解决了代码合并问题
  • 1.2. 自定义flutter_webview库后,便于依赖处理及版本控制,搭建dart私服
  1. 两个不同的库同时依赖flutter_webview,导致官方依赖和自定义库依赖冲突,编译不通过问题
  • flutter_html库依赖flutter_webview,下载最新的flutter_html代码,并添加两个源(官方git源+公司git源),修改flutter_webview为私服地址,并上传到私服
  1. 编译问题 升级最新flutter sdk,发现有些库不支持 以往碰到这种问题,可能就会妥协,不在进行flutter升级,因此导致更多的潜在问题(flutter本就是新技术,不管sdk还是依赖库不能及时版本迭代是万万不可行的),但有私服后,这不是问题
  • 比如:依赖库flutter_verification_box 不支持flutter 2.8.1,原因就是 2.8.1后 WhitelistingTextInputFormatter弃用,下载最新代码,添加两个git源,修改如下,并发布到私服,添加到项目依赖,这样flutter升级不受影响
# WhitelistingTextInputFormatter(RegExp("[a-zA-Z]")) 修改为:
TextInputFormatter.withFunction((oldValue, newValue) =>
    RegExp(r'(^\-?\d*\.?\d*)$').hasMatch(newValue.text) ? newValue : oldValue)

四、踩坑过程有很多,列举一二:

  1. 公司UA判断问题 写了两个app的版本,导致后台无法判断,导致js回调失败
  2. js调用原生 android和ios不一致问题,及中间双引号问题
  3. 搭建私服,翻墙及验证问题
  4. android和ios拦截url处理方式不同问题
  5. 编译官方webview_flutter_android 出现问题,compileSdkVerson 31降为30即可
附:flutter_webview3.0 源码流程分析梳理及对应plantuml
xx
xx

plantuml

@startuml


actor user

user -> webview : 集成flutter层webview

webview -> webview : initState 初始化 \n _platformCallbacksHandler \n _javascriptChannelRegistry
webview -> SurfaceAndroidWebView : build \n Webview.platform.build(各种初始参数和回调) \n webViewPlatformCallbacksHandler javascriptChannelRegistry creationParams\n 进入到 webview_flutter_android项目 flutter层
SurfaceAndroidWebView -> SurfaceAndroidWebView : build() \n 返回WebViewAndroidWidget
SurfaceAndroidWebView -> WebViewAndroidWidget : build 返回 WebViewAndroidWidget \n WebViewAndroidWidget继承自statefullwidget

WebViewAndroidWidget -> WebViewAndroidWidget : 构造参数 creationParams callbacksHandler \n javascriptChannelRegistry \n onBuildWidget
WebViewAndroidWidget -> WebViewAndroidPlatformController : initState初始化 WebViewAndroidPlatformController
WebViewAndroidWidget -> PlatformViewLink : onBuildWidget
PlatformViewLink -> PlatformViewLink : onCreatePlatformView 返回 PlatformViewsService.initSurfaceAndroidView

PlatformViewLink -> WebViewAndroidPlatformController: create WebView
WebViewAndroidPlatformController -> Webview: create WebView
Webview -> WebViewHostApiImpl : createFromInstance 
WebViewHostApiImpl -> InstanceManager.dart : addInstance(id,webview)
WebViewHostApiImpl -> BasicMessageChannel : 到达原生层 create
BasicMessageChannel -> WebViewHostApiImpl.java : WebViewProxy.create 原生webview 

PlatformViewLink -> PlatformViewLink : surfaceFactory 返回 AndroidViewSurface 

WebViewAndroidWidget -> PlatformViewLink : WebViewAndroidWidget build返回 \n onBuildWidget(WebViewAndroidPlatformController)参数调用 \n 

PlatformViewLink -> WebViewAndroidWidget: 返回原生View

WebViewAndroidWidget-> SurfaceAndroidWebView: 返回原生view

@enduml
上次编辑于:
贡献者: 雷勋