「个人app」2024年的第19周(做了个大决定💪🏻 💪🏻 💪🏻 )
前言
距离上次更新已经很久了为啥鸽了这么久?以前个人APP采用原生+java springboot方式实现的, 这就带来一个弊端要维护两套代码 + 一套网页端。 所以在经过深思熟虑后【看见了小伙伴 Requable以后 坚定了信心换 Flutter 】。
是的你没有看错 Flutter + java springboot,所以就有了现在的模式,重大转变以后有啥改观呢?
- apple store 能够发布了, 这样用户接触面上就大了一倍。
- 手机网页端完全和原生APP功能+交互同步了。
截止发文章Android、iOS 均已已经审核通过并上线了。
直接放图,先看成果
和大家分享一下这个过程,如果有打算上架或者操作的有个参考。
原生切Flutter
首先还是得找个学习网站 中文版 | 英文版, 快速学习浏览一遍后就是照猫画虎了, 从github 找个开源的Flutter项目参考学习下。 开始搭建应用:dart语法学习、状态管理、网络通信、插件、图片加载、数据存储、路由管理... 和原生APP构造大差不差,然后就是UI构建。 于是就有了接下来的页面:
| 首页 | 打卡 | 学校列表 | 我的 | 学校 |
|---|---|---|---|---|
市场上架
APP首版完成开发以后最重要的就是上架了,应用市场大致分几类:Android、鸿蒙、iOS、海外。
要提前准备的物料:市场图、各种资质、授权、隐私政策。
应用市场
Android端几个大的渠道:小米、荣耀、华为、百度、应用宝、360、阿里、OPPO、vivo
iOS、鸿蒙、GoogleStore: 官方独家
Android
隐私合规
先说大概说一下厂商的审核机制: 机审 + 人工
机审:安卓端的主要是史宾格【百度旗下】、小米隐私合规扫描等各种厂商自己开发的,先说下小米比较特殊他的机审是多引擎监测,就是自己的隐私合规+ 三方的比如百度的,这个就比较开明了,其他的几家都是只会用自己的。
机审的几个方向:
- 首次安装必须以弹框形式告知用户隐私协议、用户协议等,且在此之前不能调用任何涉及隐私的方法,比如传感器 【这块后面会重点说下】
- 隐私政策文件中描述的敏感权限是否和实际运行时获取的匹配,这里要求APP中声明的敏感权限在隐私合规中都要体现关键字。
- 三方插件、SDK这种必须要在隐私政策中体现,比如: 友盟、极光、融云im等
- 各种权限及服务调用的频次不能过于频繁
人工审核需要注意的:
- 华为:用户注册、登录、注销 要严格按照审核要求来, 页面涉及个性化推荐、定向推送、精准营销的 一定要有开关以及在隐私政策中有体现。 APP不能有明显bug,测试会走一遍基本的账号流程。
机审关于隐私政策:
- 弹框形式告知用户隐私协议,且在此之前不得申请任何权限、传感器、隐私数据收集 Android 纯原生的处理方式:
- SDK初始化延迟、 用户同意后再初始化
在提审百度、小米的时候都被拒了,提示
android.hardware.SensorManager.getSensorList(SensorManager.java:436)<---p1.d.c(Unknown Source:3)<---p1.d.a(Unknown Source:6)<---p1.b.c(Unknown Source:7)<---p1.b.<init>(Unknown Source:10)<---p1.a.i(Unknown Source:42)<---io.flutter.embedding.engine.c.h(Unknown Source:113)<---io.flutter.plugins.GeneratedPluginRegistrant.registerWith(Unknown Source:68)<---java.lang.reflect.Method.invoke(Native Method)<---v5.a.a(Unknown Source:21)<---io.flutter.embedding.android.e.q(Unknown Source:9)<---com.xiaoxinbao.android.MainActivity.q(Unknown Source:5)<---io.flutter.embedding.android.f.q(Unknown Source:58)<---io.flutter.embedding.android.e.onCreate(Unknown Source:13)<---com.xiaoxinbao.android.MainActivity.onCreate(Unknown Source:0)<---android.app.Activity.performCreate(Activity.java:7070)<---android.app.Activity.performCreate(Activity.java:7061)<---android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)<---android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3067)<---android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3191)<---android.app.ActivityThread.-wrap11(Unknown Source:0)<---android.app.ActivityThread$H.handleMessage(ActivityThread.java:1921)<---android.os.Handler.dispatchMessage(Handler.java:106)<---android.os.Looper.loop(Looper.java:164)<---android.app.ActivityThread.main(ActivityThread.java:6843)<---java.lang.reflect.Method.invoke(Native Method)<---com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)<---com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
把APK直接拖到Android Studio找到p1.b.c 对应就是
class MainActivity : FlutterActivity() {
//注册所有plugin插件
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
...
}
}
但是在Flutter 项目中就比较麻烦了,在自己项目中可以在弹框后做各种初始化,但是使用yaml引用各种三方SDK插件在Android编译打包的时候是自动统一生成的。Adnrodi/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
val channel = flutterEngine.dartExecutor.binaryMessenger.let {
MethodChannel(
it,
FLUTTER_CALL_REGISTER_PLUGIN
)
}
channel.setMethodCallHandler { call, result ->
// 处理来自Flutter的方法调用
when (call.method) {
"registerPlugin" -> {
// 实现你的方法逻辑
GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine)
result.success(true)
}
else -> {
result.notImplemented()
}
}
}
try {
flutterEngine.plugins.add(QuickActionsPlugin())
} catch (_: Exception) {
}
try {
flutterEngine.plugins.add(SharedPreferencesPlugin())
} catch (_: Exception) {
}
try {
flutterEngine.getPlugins().add(WebViewFlutterPlugin())
} catch (_: Exception) {
}
val preferences = context.getSharedPreferences(
SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE
)
if (preferences.getBoolean(KEY_PRIVACY, false)) {
super.configureFlutterEngine(flutterEngine)
}
}
然后就是复现以及修改了,坑又来了。自己小米手机首次安装未点击同意,查看权限使用记录是空的,点击同意后才有设备传感器使用。这怎么办? 无法复现这样就算修改了也不好测试。
- 1、盲改开始:网上找了一圈都是使用FutureBuilder去异步加载runApp(XiaoXinBaoAPP());
- 2、开心提审被拒,以为是应用市场缓存包的原因重新提升百度、小米,再次被拒。
- 3、不应该啊是不是他们有bug 再次提审再次被拒。
- 4、略带喜感,会不会是百度检测引擎坏了,换小米试试
- 5、依旧翻车,痛定思痛,应该是真有问题。
分析后发现:
yaml引用的插件中有获取设备传感器的,并且在初始化的时候就调用。所以只要延迟这些插件的初始化就行了。
但是具体操作起来就麻烦了,APP进入后要先获取是否同意隐私政策就涉及到SP的插件,如果统一延迟就无法获取是否同意隐私政策, 而且弹框上面有网页跳转,而网页的跳转是使用webview插件的就会导致跳转是白屏。综上就得改成初始化部分插件,涉及隐私政策的延迟初始化。
问题:
- 全部延迟以后会导致部分功能异常
方案:
- 部分初始化、部分延迟
实施:
- 修改自动生成GeneratedPluginRegistrant.java 【不可行,每次又被自动编译覆盖了】
- 修改生成类的插件,然后按需生成代码 【尝了了下,工程有点大】
- GeneratedPluginRegistrant的入口处拦截处理 【可行】
flutter pub get以后插件会基于yaml然后生成GeneratedPluginRegistrant.java,所以直接修改产物会被覆盖,接下来就得找到GeneratedPluginRegistrant.java的调用处,经过分析发现 FlutterActrivity.java 在:
/**
* Hook for subclasses to easily configure a {@code FlutterEngine}.
*
* <p>This method is called after {@link #provideFlutterEngine(Context)}.
*
* <p>All plugins listed in the app's pubspec are registered in the base implementation of this
* method unless the FlutterEngine for this activity was externally created. To avoid the
* automatic plugin registration for implicitly created FlutterEngines, override this method
* without invoking super(). To keep automatic plugin registration and further configure the
* FlutterEngine, override this method, invoke super(), and then configure the FlutterEngine as
* desired.
*/
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
if (delegate.isFlutterEngineFromHost()) {
// If the FlutterEngine was explicitly built and injected into this FlutterActivity, the
// builder should explicitly decide whether to automatically register plugins via the
// FlutterEngine's construction parameter or via the AndroidManifest metadata.
return;
}
GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
}
有了入口就是大致思路了:
- 拦截入口,按需加载,同意隐私政策后全部加载。
- 1、重写configureFlutterEngine 移除super
- 2、按GeneratedPluginRegistrant的注册方法手动加载需要的插件 SP、webview... 【GeneratedPluginRegistrant是根据类名防止重复的,所以不用担心多次初始化】
- 3、注册MethodChannel然后在Flutter同意后调用GeneratedPluginRegistrant的全部初始化。
改完以后提审,百度、小米机审一次通过🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉
ICP、安全合规备案、软著
ICP备案:个人的话大致几个方向 博客、个人主页,剩下就是按流程都能办下来的,【审核两周左右吧,不一定】
软著 :自己申请按流程填各种表格,需要注意的是源代码60页,大于的话要前30页,后30页、 第30页要断行。【耗时较长】
APP备案:因为网站、服务器备案过以后 APP的备案只是在原有主体新增一个【耗时:ICP备案过以后很快,可以同时进行】
安全合规备案:提供带有社区性质、舆论性质的才需要申请,需要有敏感词、封禁、鉴黄等功能,这个有点麻烦要和所属地网安打交道 【个人建议功能非必要先不加这个功能,不然很难申请】
苹果
账号需要588人民币,如果有拖延症的可以先买账号,然后倒逼开发进度。 因为每年都要续费
内购、订阅机制、资质
- 5月1日后需要APP备案才能上架,隐私合规+资质比Android市场要少一些。
- 内购、订阅 需要测试环境审核
- 市场图需要和APP内容一致,不能差的版本多
打包上架、Deeplink、微信登录
- 以后再聊
GoogleStore
和苹果一样账号需付费但是是一次性的
总结下
- Flutter组件学习、dart语法、kotlin、js、java、python 看多了以后相通的很多,有个巨大的后遗症就是混乱了,有时候编译器报错一看提示js写到dart上了,有时候快捷键等半天不响应一看有些语法不具有那些语法糖。
- 船小好调头,相较于成熟或者公司性质的,单从原生切Flutter做决定就得好久。这也是优势,可以快速迭代试错。
- 诚邀体验,提bug。 目前除OPPO、vivo手机搜不到。其他的在应用市场都能搜到了,关键字:『校信宝』
接下来方向
- 更多是产品方面的思考,大方向是不会变的:提供一个供高考学生查询的工具,基于学生自身的优缺点系统性的提供一个科学的报告,基于这份报告匹配合适的学科+学校。 更像是一个多维图,只要构建的维度足够科学、详细,那匹配的学校+专业也就更加精准、合理。