Flutter 开源项目(一) - 文件管理器
朋友们,好久不见,很久没有在掘金发布过文章了,大三的时间的确是非常匆忙,已经下定决心入坑Flutter
行业的我也需要成天的学习 web 开发了。
声明
仅以学习为目的,对于个人文章或者代码写的不好,导致你在某些工作上使用了我的代码而带来的负面效果,而我就需要承担一些人损失多少多少钱的责任这一说,我不赞同,如果有请绕道。
写的烂的我在努力写好了。
开源的库并没有到一个很稳定的版本,所以说都是仅供参考学习,我会持续对每一个开源库进行维护。
前言
我把我大学的前两年的绝大部分开发时间分给了我的个人项目魇·工具箱
,由于其中的ROM工具
是付费功能,起初我把各种各样的功能代码都写在一个项目中,从初学Flutter
就开始了这个项目,项目中代码水平参差不齐,越到后面我发现维护越来越困难,代码虽然只有几w行,但对于个人来说几乎到了没法维护非付费功能的一个地步,也经历了很多次的重构,每次重构也必会代码大量的bug。
我希望把工具箱的各个功能进行模块化,能够无缝的集成在任何项目中,一方面也是方便个人维护,,而非付费的模块,我会依次开源到个人储存库。
先上开源地址吧
termare:针对个人终端模拟器成立的组织。
nightmare-space:个人项目的开源组织。
相关文章
开源列表
- 文件管理器
- 刷机工具
- ADB 工具
- 终端模拟器
支持功能列表
- 文件选择
- d
- Apktool(仅限安卓)
- 书签管理
我也清楚作为一个文件管理器来说这样的功能是远远不够的,但是时间的确有限。
目前个人会用到的仅有反编译与文件选择功能。
使用集成
就像下面这样简单。
相比原生文件选择器
- 首先 app 的启动自身是具有一个独立的 uid/gid 的,所以由这个 app 启动的所有进程都是带有同样信息的,那么用
dart
的api
始终拿不到
高级权限,永远只能访问沙盒数据。 - 由于我们不仅仅是需要有选择文件的功能,我们还需要扩展文件管理器的功能。
截图
开发遇到的问题
分享处理问题思路
Flutter 相关
其中遇到的两个问题就是,路由的管理与状态的管理
MateriapApp 带来的路由问题
我们通常的 app 的顶层会有一个 MaterialApp
组件来获得一个初始的路由,而如果不适用MaterialApp
组件页面就会爆红很多组件,个别组件套上Material
即可,其他的一些组件是一定要祖先节点有MaterialApp
(或者CupertinoApp
、WidgetsApp
),在写这个文件管理器
我也同样给顶层加上了一个MaterialApp
,在调试example
也没有遇到任何的问题,但在集成到主项目后,路由的管理就会特别的麻烦。
场景如下:
在项目A
中集成了B
,B
在组件上套有MaterialApp
,在A
中的页面 push B
,随后B
项目内部调用Navigator.of(context).push
这个时候就会发现,B
拿到的Navigator
是B
中MaterialApp
下的,这个时候我们按下返回键,最后执行的Navigator.of(context).pop()
中的context是A
中的,所以不管B
路由了多少次,都会被整个pop
掉。
这个问题的确是新手级别的,但是最初我的解决方向是在
B
上拦截返回按键,然后越处理越不对劲,所以我最后取消了组件的 MaterialApp。
页面级别的状态管理
我个人最初在组件的上层套上MaterialApp
的原因就是,我需要用一个在MaterialApp
上的Provider
,这样一来我不管是单页面,还是路由,能轻易的通过Provider.of(context)
拿到一个祖先节点的状态实例,但是由于上个问题带来的影响,我于是取消了MaterialApp
,于是在页面内进行路由的时候,不管怎样我都不能通过Provider.of
找到含有实例的祖先节点。
当时咨询到和想到的几个方法:
- 拿实例的页面路由到第二个页面的时候将实例传进去。
- 将
context
通过参数传到第二个页面。 - 将数据存进单例。
我最后放弃了这个思路,如果我还有n个页面需要路由,那么我需要给每个页面的构造函数添加一个参数,亦或者是通过路由参数的方法,这样不用更改构造函数,但是个人觉得获取路由参数是非常不可控的,即使我忘记传这个参数,在新页面获取理由参数的地方编辑器是不会提示出错的,只会在使用的时候才能看到错,我觉得这样不利于维护。
最后解决方法:
通过单例的方式,在第一个页面拿到状态实例的时候将实例保存在单例,第二个页面直接通过单例取数据,通过addListiner
、removeListiner
的方式来同步UI的更新。
1 | class Global { |
Apktool移植到安卓
这虽然不是处理耗时最久的问题,但对当时的我,是最难的问题。
整个处理都在一年前了,有些想不太清了。
在次之前已经有个比较出名的app->Apktool
,名字就叫这个,我从安卓2.1的时候就在使用这个app,出自国外的大佬。
Apktool App的思路:交叉编译java
环境, 随后的所有操作,打开一个Linux Shell
去run apktool.jar
就行了,
缺点:jdk的集成导致数据直接上100m
,这也是我最不想看到的,作为一个dart package,我肯定不希望别人集成后直接app
1个G是吧。
个人尝试过的思路
将apktool.jar 转换为 dex
理由:dex
文件可直接在安卓端启动,利用dalvikvm
,app_process
这是我在看了很多优秀的开源库的做法,往往想要安卓设备上运行java代码,通常就是将
.jar
文件转换成.dex
二者区别
- jar 内是.class文件,java 虚拟机的字节码。
- dex 反编译得到.smali文件,是安卓虚拟机的字节码
dalvik虚拟机是基于寄存器的,而jvm是基于栈的.
首先在转换上就遇到了非常多的问题,对dx命令的使用,因为还有一个叫dx8的工具,二者是不一样的,主要是要加上一堆的参数,-h
只能知道参数是干嘛的,比如你知道-api
是指定android 版本,但你不知道你是这个参数不对转换出错,也不知道具体要调成多少才能转换成功,
最后总算是转换成功了。
- 反编译正常,但效率低下(相比
Apktool x
这个app) - 回编译卡住,原因未知,试过
logcat
,始终没有找到原因。其实单从第一条来看我就已经放弃这个思路了。
在安卓项目中引入 apktool
gradle中引入
我当时就想,一些平台的SDK
也是.jar
,里面也是.class
,引入后也能直接打包进app
内的dex
下,而且在java就能直接调用。
apktool.jar是一个java的命令行工具,之所以能成为命令行工具是指定的类带有main
函数,我以同样的方式引入后直接调main函数不就行了。
反手gradle引入 -> 报错一气呵成。
1 | dependencies { |
上面还有一行是apktool,现在找不到地址了,然后就以这样的方式引入后,构建的时候,报错一堆。具体是直接 implementation 引入还是下载了 jar 再引入记不清了。
我当时就奇了怪了,都是java,没理由啊。
随后 clone 下apktool
的所有代码,将代码 copy 到项目,ok,爆红的地方终于找到了,apktool.jar
在处理apk
内的.9
图片的时候,用了awt
这个包,这个包在安卓的sdk
上是没有的,然后就是大量的代码修改,将awt
处理图片的地方全部换成Bitmap
,对于当时的我,实在吃力,起码花了几周的时间。
ls 输出的解析
在各个平台可能会遇到ls
命令版本不一致,或者输出不一致的问题,就会直接导致文件列表信息获取失败,但在我测试的过程中,这个都能找到规律和处理的方法。
改进方法。
其实其中有的问题都是两年前处理的了,两年前我才大一上,当时还没接触技术圈子,成天自己闷头写代码。只是很多时候回想起来,这一路还是经历过一些东西,现在都还记得。
Flutter 开源项目(一) - 文件管理器
http://blog.nightmare.press/2020/11/15/Flutter-开源项目-一-文件管理器/