Flutter 静态挂载腾讯X5WebView(Tbs)浏览器内核_flutter tbs-程序员宅基地

技术标签: dart  webview  flutter  webrtc  plugin  Flutter  


背景

项目中(Flutter项目)有一个需求是通过webview加载界面,来显示实时视频(webrtc),那么问题是,不同Android手机浏览器对于webrtc视频解码的支持性有差异导致部分手机无法正确显示视频,部分手机只有声音没有视频。那么我决定通过端侧来解决这个问题(我猜测修改web端代码进行适配也能解决),由此引申出了这篇文章,留作参考记录。涉及到的主要知识点如下:

  1. Android 平台下替换浏览器内核方案。
  2. Android Native 静态集成腾讯X5(tbs)浏览器内核。(需要原生静态集成tbs浏览器内核的同学同样适用)
  3. Flutter plugin 插件开发。
  4. Flutter 打包机制。

一、寻找Android WebView 内核替换方案(在native层面验证)

1.CrossWalk

经过测试,最新版本的CrossWalk并不能解决问题,仍然存在视频无法解码的问题。集成方式不再多说,相关教程很多。要注意的是crosswalk webview 想要略过ssl验证,需要修改源码中的SslUtil文件,修改为如下,直接忽略掉ssl异常。

 public static boolean shouldDenyRequest(int error) {
    
        if (error >= -214 && error <= -200) {
    
            switch(error) {
    
            case -213:
            case -212:
            case -211:
            case -208:
            case -207:
            case -206:
            case -203:
            case -202:
            case -201:
            case -150:
            case -129:
                return false;
            default:
                return false;
            }
        } else {
    
            throw new AssertionError();
        }
    }

然后将这个java文件编译成".class"文件后,替换到crosswalk的aar包中。我在验证过程中也做了一些工作,把用到的资源分享一下,以便有同学用得到,下面的下载链接是编译成.class的SslUtil文件(其实这个是比较难搞的),将内核的aar sdk解压替换即可,可以到crosswalk官网自行下载32or64位的sdk。
下载链接
提取码:8cy5

2.腾讯X5浏览器

另外一个方案是腾讯的X5浏览器内核(https://x5.tencent.com/),经测试,可以解决我的问题,兼容性良好,有两种集成方式说明一下

1)动态集成

动态集成具体方式官网上&其他帖子有很多说明,自行查找。经过测试,动态集成在Native项目中,内核挂载还算相对稳定(也有反复挂载不成功的情况),但是已Flutter 插件(Flutter 插件为静态集成)的方式,集成到Flutter项目后,体验非常之差,内核挂载成功率很低。所以动态集成方案pass,无法使用。(说句题外话,虽然这里只写了一段,但是验证过程确实还是用了一些时间的)

2)静态集成

那么目前就明确了两点,要解决两个问题,首先是采用x5Webview替换内核方案,其次是需要静态集成。

参考文章 原生项目需要静态集成的同学对照这篇文章集成即可。

我这里补充一下我提取到到的64位内核资源(实际提取不难但我觉得麻烦,其实用32位的so文件足够),下载链接如下:
下载链接
提取码:fmy5

到此,这两个问题圆满解决。

二、Flutter 静态集成的X5WebView 的插件开发

明确了方案,并且tbs静态集成也ok,那么下一步就是要创建一个静态集成的X5WebView的Flutter插件给Flutter项目使用,搜索了一下目前只有x5webview动态集成的flutter插件,那么这里就需要自己去搞一个插件来用,这里我借鉴了pub上已有的动态继承tbs的库。
插件提供了两种使用方式,一种是直接从Flutter界面跳转到Native方式使用了Tbs浏览器的Activity,一种是直接使用实现了TbsWebView的Flutter Widget

1.StaticTBS Flutter Plugin(插件) 开发

1)创建Flutter Plugin

as中,点击File->New->New Flutter Project ,弹出选择项目类型界面,选择Flutter Plugin,点击Next,之后填写相应信息,最后finish,完成创建。创建的项目中内含一个example目录(是一个flutter 项目),这个是用来调试plugin功能的,可作为临时宿主使用。

2)编写Android Native代码

这点比较关键的,我想通过android studio 开发原生部分的代码,关键点是,先要构建一下生成的eample项目,cd 到 example目录,执行“flutter build apk ”即可,构建完成(是否成功不重要),之后就可以通过android studio 打开项目进行native开发,要注意的是,要打开example里面的android项目。

plugin project结构
将提取到的armeabi架构的tbs so库文件以及,静态加载用到的jar包导入项目。

3)编写Flutter插件代码

这里涉及到的代码以及知识点较多,主要是插件开发相关,后面我也许会单独写文章记录,就不在这单独讲解了,可以搜索Flutter Plugin插件开发相关文章,目前项目已上传到git,请自行查看
插件项目地址

三、集成插件项目的编译

使用静态tbs插件后,直接打包还是会发现内核挂载失败,核心问题就是我目前还没有提取到不同架构下的tbs so库,只提取到了armeabi架构的,受限于tbs挂载规则或者是flutter so加载机制,tbs的armeabi so库并不能向上兼容,放在armeabi-v7下不不好用。只能放到armeabi文件加下才可以保证加载成功,所以还需要关注一下下面的说明

1. 针对“Shrink”做的修改

当项目集成了静态内核,会发现还是无法挂载,是因为flutter的打包apk机制 ,进行了“shrink”操作,将“com.tencent.cmtt” 包下的“utils”文件夹给“优化”掉了,误伤友军,所以为了能正常挂载静态内核,那么需要对flutter gradle文件进行修改。

Flutter 本身gradle的文件路径 :
D:\你的flutter本地源码文件夹\flutter_windows_v1.9.1+hotfix.6-stable\flutter\packages\flutter_tools\gradle

打开这个路径下的“flutter.gradle” 文件进行修改,修改这个部分代码,将注释部分屏蔽掉,这样flutter工程在打包anroid项目的时候,就不会去shrink,对apk进行瘦身了,这里要注意,如果修改了flutter源码下的代码,后面想要通过“flutter upgrade”升级版本的时候会出错,需要先revert掉,才可以正常升级。

     private static Boolean shouldShrinkResources(Project project) {
    
     	//将这个函数屏蔽掉
        if (project.hasProperty("shrink")) {
    
           return project.property("shrink").toBoolean()
        }
         return false
     }

2.so库打包机制

接下来要讲一下到Flutter so 库打包机制了,这里会延伸出一个flutter常见问题“couldn’t find “libflutter.so””,特别是你通过命令行进行打包的时候更容易出现这个问题,原因稍后讲解。
当解压正常的Flutter apk包,我们可以看到lib下的armeabi,arm64-v8a,x86等文件夹下会有“libflutter.so”以及“libapp.so”这两个文件,可以这样理解,libapp.so他就是我们用flutter写的业务逻辑所打包的产物,libflutter.so实际上可以理解为libapp.so执行所必备的环境之一,正常运行的时候根据手机架构加载对应的so库,达到native层面优化的效果。
那么回到上面的问题上来,“couldn’t find "libflutter.so”导致崩溃,极大概率就是你使用了一些plugin,或者是引用了一些第三方库文件,打包时导致slibflutter.so库没有被打到指定的文件夹下,导致应用崩溃,如果是libapp.so没有被打进去,应用只是会白屏,因为找不到UI以及逻辑代码。
解决这个问题需要你理一下你项目中用到了哪些第三方so库,特别关注plugin,然后可以通过修改android目录下的ndk打包模式来进行调整。
修改的位置如下图:
Android gradle 配置修改
有两种情况
如果你只打算适配arm架构,那么就修改为只打包armeabi-v7即可,你需要保证所有的so库,都有这个架构的so文件。
这里有一个坑,flutter现在打包默认不支持将libflutter.so以及libapp.so打到armeabi下,如果你想向上兼容,只对armeabi做适配那是行不通,这里有个骚操作,那就是先生成armeabi-v7 的apk,解压后拿到这两个so库,手动复制到armeabi目录下,在进行只有armeabi架构的打包,就可以了,是有些麻烦,注意,目前如果使用这个插件,需要按照这个步骤操作。
其实也可以修改flutter gradle文件,让它可以将这两个so文件打包到armeabi目录下,不是很好搞。

如果你打算适配不同架构,核心就是要不把不同架构so库找全了,全部统一到对应so目录下,在进行打包。

如果还是有问题,有个排查技巧,拿到启动会崩溃的apk,丢到as里面,查看lib文件,可以看到哪些so文件出了问题,这样比较直观
不同架构so库分析
上图所示,armeabi有41MB,是因为我把tbs浏览器内核放到了armeabi文件夹下,打包的是全平台,所以其他三个下面没有这些so文件,所以如果运行在arm64,x86设备上,内核是会挂载失败的。

总结

总结一下心得:
首先这边博客还只是算是给出了解决思路,实际看起来有些杂乱,杂乱的原因是目前我这个方案肯定不是最优解,需要后续完善,这里做一下记录,如果能吸引到牛人来一起探讨那更好了,我下一步的思路就是继续尝试修改flutter gradle,让flutter支持打包armeabi架构的apk,因为时间不是很多,之前只是简单试过没有成功。如果哪位有思路欢迎交流。

近期的一些思考
对于技术,每一个点,往细了深究都会牵扯到好多东西,需要静下心来去研究,试错,尽可能的使点连成片。以这篇文章来讲,我还有好多地方做的不过好,需要后续改进。
对于项目,不同业务情况不同的分析方式,面对不同Bug也要有不同的解决思路,具体问题具体分析,不要局限于一小块,已万变应对不变。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yyfd2013/article/details/108225667

智能推荐

openstack多个外部网络可能引发的网络问题_openstack路由接口down-程序员宅基地

文章浏览阅读2.9k次。在多个外部网络的环境中,如果_openstack路由接口down

ios NSString 截取汉字 数字 字母-程序员宅基地

文章浏览阅读232次。字符串截取:删除字符串中的字母+汉字NSString *string = @"你bushi1222真正90-快乐";NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:@"[a-zA-Z\u4e00-\u9fa5]+" options:0 error:NULL];resul..._ios 字符截取数字前面的字母怎么弄

RuoYi-Vue(SpringBoot+Vue+Socket.IO) 实现消息推送功能_vue消息推送功能实现-程序员宅基地

文章浏览阅读1.1k次,点赞10次,收藏14次。使用 ruoyi-vue 实现实时消息推送,可向指定在线用户推送_vue消息推送功能实现

C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏7次。本文介绍 头文件中最简单的原子类型: atomic_flag。atomic_flag 一种简单的原子布尔类型,只支持两种操作,test-and-set 和 clear。std::atomic_flag 构造函数如下:std::atomic_flag 只有默认构造函数,拷贝构造函数已被禁用,因此不能从其他的 std::atomic_flag 对象构造一个新的 std::atomic_flag 对象。如果在初始化时没有明确使用 ATOMIC_FLAG_INIT初始化,那么新创建的 std::atomic_fl_atomic_flag

在slicer中编写scripted模块_attempting to build the python scripted module 'su-程序员宅基地

文章浏览阅读306次。无摘要_attempting to build the python scripted module 'surfacetoolbox' when slicer_

获取Form.ShowDialog() 出的窗体中textbox的返回值_this.getformref().-程序员宅基地

文章浏览阅读540次。转自 : http://blog.csdn.net/piaofengxiyue/article/details/4494382经常会遇到ShowDialog出的窗体中有一些textbox,输入完后返回到主窗体中。怎么办呢?有办法。 理论上讲ShowDialog后的窗体返回值类型是DialogResult。也就是一个枚举值,只有yes,no,ok之类的值,肯定是不_this.getformref().

随便推点

[Android]-[adb] user版本开启adb且去掉adb授权弹框_免adb授权修改-程序员宅基地

文章浏览阅读2.3k次。配置两个属性即可:1.使user版本可以adbdevice/mediatek/mt6739/device.mk ifeq ($(TARGET_BUILD_VARIANT),user)- PRODUCT_DEFAULT_PROPERTY_OVERRIDES += persist.sys.usb.config=mtp+ PRODUCT_DEFAULT_PROPERTY_OVERRIDES += persist.sys.usb.config=mtp,adb2.去掉user版本授权usb弹框b_免adb授权修改

FreeBSD软件安装卸载工具:Ports和Packages详解-程序员宅基地

文章浏览阅读432次。FNP:FAQ - Ports and Packages v 1.52004.08.20 Table of Contents1、如何只抓取 tarball?2、如何仅做到解开 tarball的步骤?3、如何仅做到解开 tarball 并补上官方提供的 patch?4、如何安装一个新的 port?5、如何安装一个新的 port,并将打包(package)起来?6、如何打包一个 port,并将其所有相..._linux ports

终于,狂神说SSM及SpringBoot系列文章完更!!!_狂神博客-程序员宅基地

文章浏览阅读10w+次,点赞1.3k次,收藏8.5k次。经过了近一个月的时间,小狂神终于将SSM及SpringBoot视频对应文章更新完毕!!!记得文末喜欢走一波,码字不易,从公众号开通,就保持日更,何尝不是一种打卡呢?你们都坚持看了吗~如果..._狂神博客

HDFS的EditLog和FsImage作用详细解析,超详细!(含部分非原创图片,大部分原创总结)_hdfs editlog-程序员宅基地

文章浏览阅读698次,点赞7次,收藏10次。EditLog和FsImage的概念,以及与SecondaryNameNode的关系问题,以及EditLog和FsImage的重要性问题。_hdfs editlog

JS 系列之 事件—表单事件_js input event-程序员宅基地

文章浏览阅读2.6k次。今天跟大家分享一下JS系列之表单事件。1 表单事件的种类1.1 input 事件input事件当、、的值发生变化时触发。对于复选框()或单选框(),用户改变选项时,也会触发这个事件。另外,对于打开contenteditable属性的元素,只要值发生变化,也会触发input事件。input事件的一个特点,就是会连续触发,比如用户每按下一次按键,就会触发一次input事件。input事件对象..._js input event

菜单下拉条-程序员宅基地

文章浏览阅读82次。最近 ,用到了一些js的知识,稍微复习了下,还把之前写的js代码又复习了一遍,这里贴上来!<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http:/..._菜单下拉条