范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

AndroidAPP出海实践

  当前国内各个公司 APP 出海创收已经是互联网行业的常见操作。笔者最近约 2 年的时间里,都在进行云音乐旗下首个出海应用 Android 客户端的开发。本文对海外 APP 一些开发经验做一些分享。
  初次出海的时候,我们总结了需要适配海外环境的方方面面,包括 客户端内的很多通用模块需要支持海外环境。这里包括 确认一些三方服务对于海外环境的支持程度,例如云信、声网 SDK 一些常见 APP 功能的海外版本封装,例如登录,文件上传,推送,分享 底层库功能自查,支持上架政策和一些资源配置。 我们的目的是,尽量保持原有的技术框架去开发新的 APP,不要因为运营环境变了,技术架构也大改。 Android APP 的发布渠道和发布格式。海外 Android 应用以 Google Play 上架发布为主,这里我们需要额外支持 aab(android app bundle) 格式进行发布。 海外应用设计基础库海外实现层
  基础模块我们遵循接口实现分离的设计原则,以文件上传底层库为例,我们会有3个最终打成 aar 的 module: uploader_interface 提供文件上传相关的各种接口 uploader_module uploader_interface module各个接口的具体实现,例如文件通过中台的 CDN 接口上传。 uploader_module_oversea 同样是 uploader_interface module里面各个接口的具体实现,实现逻辑从直接 CDN 接口上传改为先上传至亚马逊云,然后把亚马逊云的上传信息同步给 CDN。
  得益于上面的设计原则,基础模块我们只需要提供对应的海外实现即可。业务代码内调用的仍然是接口 module 的 API,这样做一来一些依赖底层的业务代码可以直接复用,二来开发同学也不需要再去熟悉另一套底层库 API。
  底层库合规检查
  海外 APP 在 Google Play 作为主要分发渠道的情况下,隐私政策可能和国内略有不同。而一些底层库可能包括了一些不合规的代码,这部分需要进行排查,一般来说,遵循下面 2 个原则就不容易出现问题: 底层库代码里面没有违规的 API 调用,例如和热修复这种动态代码下发的。Google Play 不允许相关功能 底层库的依赖里不要包含海外环境用不到的功能。例如一些之前全公司 APP 都通用的三方服务的SDK被集成在了某个底层库,虽然海外没有使用相关功能,但是这些 SDK 非常有可能因为包括了动态下发 so 而被检查出来。
  Google Play 隐私政策可以参考
  support.google.com/googleplay/…
  底层库资源
  另一方面,对于比较简单的底层逻辑,我们一般情况也不会对其做接口与实现拆分,但是底层有可能会使用一些通用的资源,例如文案、图标等。如果我们把这些值作为变量设置进去,一方面底层库的改动比较大,另一方面初始化时候的设置也非常的繁琐。这里我们可以利用 Android 自身的资源合并策略。
  如上图,底层库里面定义的 key1 字符串,我们在上层定义同名的字符串 key2, 最终在打包的时候,资源合并会保留 key2。所以也需要我们在设计底层库的时候避免直接使用字符串硬编码,以免不能灵活支持海外应用。 aab 文件与 Play Store 分发app bundle 格式
  使用 app bundle 格式当下在 Google Play 进行分发是唯一选择。
  我们使用 ./gradlew :app:bundleRelease 复制代码
  构建我们的 app bundle 文件上传至 Google Play 后台进行发布。
  但是由于 aab 文件并不能直接安装在设备上,所以在日常的测试、回归阶段,我们仍然是安装 apk 文件来进行,流程如下图:
  从理论上来说,apk测试回归没有什么问题,aab 也就没什么问题。但是在日常实践,我们可能会有一些 Gradle Plugin 的 task 在 hook 一些编译任务的时候,忽略了 aab 的情况,从而导致一些运行时的错误。针对这种情况,在正式的 aab 文件发布前,我们还是有必要对其做一个快速的走查。
  Google 官方也提供了方法让我们安装 aab 文件到设备上,使用 bundletool 工具根据 aab 文件生成 apks 文件,然后使用 adb install-multiple   命令安装:java -jar bundletool.jar build-apks --bundle=${FILE_NAME} --output=${target_apks} unzip target_apks cd splits adb install-multiple bae-master.apk xx.apk 复制代码
  这样测试回归流程则可以加上 aab,但是让 qa 同学每次使用脚本安装总也是个麻烦的事情,所以能否更彻底点呢?答案当然是可以的,既然可以通过 install-multiple   安装 apks 文件,那么 CI 流程上每次 aab 构建的时候,输出 aab 和 apks 2个产物,然后通过一个安装 apks 文件的 APP 进行安装。
  我们可以通过 android.content.pm.PackageInstaller   这个 Android API 实现这个功能
  代码如下:val installer = InstallApp.application().packageManager.packageInstaller val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) val sessionId = installer.createSession(params)  val installSession = installer.openSession(sessionId) apks.forEach {     installSession.openWrite(it.hashCode().toString(), 0, -1)         .use { out->             FileInputStream(it).use {fin->             val buffer = ByteArray(16384)             var len: Int             while (fin.read(buffer).also { len = it } != -1) {                 out.write(buffer, 0, len)             }         }         installSession.fsync(out)         installSession.close()     } }  val intent = Intent(InstallApp.application(), RetActivity::class.java) intent.action = PACKAGE_INSTALLED_ACTION val pendingIntent = PendingIntent.getActivity(InstallApp.application(), 0, intent, FLAG_MUTABLE) val statusReceiver = pendingIntent.intentSender installSession.commit(statusReceiver) 复制代码
  安装结果我们可以通过 Intent 里面的 android.content.pm.extra.STATUS   获取。
  这里我们就可以不适用脚本命令行,直接使用安装工具安装aab文件,app 的回归发布流程就比较完善了:
  Google Play 签名
  Android 应用通过 Google Play 发布的时候,还需要开启 Google Play 应用签名功能,具体的操作和规则可以参考 Play 管理中心文档:
  support.google.com/googleplay/…。
  按照官方图示,Google Play 会把开发者上传的密钥重新签名为新的密钥进行发布。
  最终 Google Play 控制台里面会显示最终的密钥指纹和上传密钥指纹:
  Google Play 之所以设计这套看起来有点复杂的秘钥管理,是为了保障 APP 的签名安全。当我们的上传秘钥出现被盗取或者丢失的情况下,也只需要申请重新替换上传秘钥即可。 但是我们的 APP 在发布的时候,我们不仅需要在 Google Play 进行发布,还需要发布自己的 APK 渠道包。在后台升级密钥的时候,会有如下几个选项
  如果使用默认的 Google Play 生成新的密钥,我们只能导出一个后缀名为 der   的证书,这个证书里面只包括了公钥,所以即使同 keystore 工具导出 jks 文件,也不能正常打包。所以我们需要选择 "从Java密钥库上传新的应用签名密钥"
  这里还需要注意一点,选择新的密钥规则默认选择 Android T 及以上版本升级,且此选项默认收起。我们需要选择下面的 "所有Android版本的所有新安装",否则无法达到最终目的。
  所有我们最终签名流程如下图所示:
  我们拥有 2 个打包签名文件,分别为 release.jks 和 store.jks,通过 Google 的 pepk.jar 工具把 Google Play 的签名换位 store.jks。最终在发布的时候:aab 文件使用 release.jks 构建,上传后会重签为 store.jks 发布release 渠道包的apk文件使用 store.jks 构建,这样 apk 和商店下载的 aab 文件签名才一致,才能算是同一个 APPGoogle Play 发布问题
  在使用 Google Play 发布的时候,如果我们使用了 uses-feature   声明功能的时候,最终在发布的时候,可能会导致最终发布后显示支持设备类型数为 0,这样用户将无法下载甚至无法在 Google Play上看到该版本。
  我们需要在声明的地方添加上 android:required="false"  即可。为了避免底层库和上层的定义有矛盾导致 AndroidManifest 合并出错,我们可以通过 Gradle 脚本修改合并后的 AndroidManifest 文件,把 reuqired 的值全部改为 true:android.applicationVariants.all { variant ->     variant.outputs.each { output ->         def processManifest = output.getProcessManifestProvider().get()         processManifest.doLast { task ->             def outputDir = task.multiApkManifestOutputDirectory             File outputDirectory             if (outputDir instanceof File) {                 outputDirectory = outputDir             } else {                 outputDirectory = outputDir.get().asFile             }             File manifestOutFile = file("$outputDirectory/AndroidManifest.xml")              if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {                 def manifestPath = manifestOutFile                 def xml = new XmlParser().parse(manifestPath)                 def androidSpace = new Namespace("http://schemas.android.com/apk/res/android", "android")                 xml."uses-feature".each {it->                     println it.attributes().get(androidSpace.name)                     if (it.attributes()[androidSpace.name] == "android.hardware.camera.front" ||                             it.attributes()[androidSpace.name] == "android.hardware.camera.front.autofocus") {                         it.attributes()[androidSpace.required] = false                     }                 }                 PrintWriter pw = new PrintWriter(manifestPath)                 def content = XmlUtil.serialize(xml)                 println content                 pw.write(content)                 pw.close()             }         }     } } 复制代码应用多语言多语言工作流
  提到应用出海,还有一个绕不开的话题就是应用多语言问题。 我们通过设置 Locale 来设置语言。并且在语言切换的时候重建 Activity:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 	config.locale = target 	res.updateConfiguration(config, res.displayMetrics) 	config.setLocale(target) 	context.createConfigurationContext(config) } else { 	config.locale = target 	res.updateConfiguration(config, res.displayMetrics) } 复制代码
  具体多语言我们会从内部的多语言平台拉取打包后的xml文件,放到对应的文件夹下。应用在 Locale 修改后会自动选择对应语言的文件。例如英文目录为 /res/values-en   ,印尼语为 /res/values-in  。流程如下图:
  随着出海APP增多及运营国家支持语种增多,上述简单的多语言导入流程也逐渐的不够使用,包括:语言较多,并且定义在代码内,每次新增语言配置都需要各个使用的地方(例如注册选择语言,设置切换语言等)修改代码。配置化程度比较低。一旦漏改,就会存在bug。从多语言平台下载文案并放入res文件夹里面的时候,需要有一个 values 文件夹作为默认语言文案,在开发阶段,我们从交互稿上看到并且录入的基本为中文,但是发布后的默认文案应该为英文。如果全程手动操作非常繁琐。
  我们使用 Gradle 插件来解决这2个问题。每个应用支持的多语言类型通过配置文件定义,Gradle 插件根据配置文件内容生成语言信息的常量代码。在编译期添加一个自动拉取多语言的 task,注册在 pre${variant}Build   task 之后。当 variant 属于 debug 的时候,res/values 里面放的为中文的xml文件。当 variant 属于 release 的时候,res/values 里面放的为英文的xml文件。
  整个 language plugin 的工作如下:
  其中,自动拉取插件在替换文案之前,还可以做一次预检查操作。防止因为翻译错误等原因导致编译报错。例如文案里面检查 1 转为 %11转为s 的时候,是否有字符缺失或者增加了空字符导致 String.format 出错文案里面存在 & 符号,需要修改为 &多语言解耦
  在 app 的日常维护中,时常会有多语言文案需要替换。在上述工作流中,非客户端开发在需要替换文案的时候,需要频繁的提问客户端开发需要替换的具体 key。这样无疑增加了需要沟通成本。我们还可以通过一些技术手段来减少这部分的耦合。 常见的文案的替换场景大概分为两类测试、走查阶段发现某些语种存在翻译缺失开新区增加新翻译的时候,某些语种的文案长度不合理需要精简 这两种场景,非开发角色不经过沟通并不知道具体的多语言 key 是什么。 针对上述两种情况,我们的多语言插件设计了两部分功能。
  缺失文案检查及 mock 文案生成 多语言插件在文案拉取的时候,对平台生成的多语言 xml 文件进行分别检查。当某语种中某个文案不存在的时候,会生成一个模拟的多语言文案写入到xml文件。模拟文案则会带上这条文案的 key。
  例如 key 为 common_hello 的文案在印尼语有缺失,那么运行时切换到印尼语时使用的文案就是 mock 的文案 "客户端mock common_hello(id)",这样 qa 或者策划看到就知道这里缺失了一条文案翻译。
  运行时查询多语言key
  当 app 业务方开发新区的时候,我们也可以把查询文案这件事尽可能的和技术剥离开。我们在 debug 运行时提供了一个悬浮窗工具,当工具开启的时候,可以选择当前页面的 TextView, 如果这个 TextView 得内容是通过 string id 加载的,那么就会把这个 key 显示在屏幕上。具体效果如下图:
  这样我们能节省开区过程中很大一部分查询多语言 key 的沟通,增加开区效率。展望与总结
  这里介绍了一些 Android APP 出海的实践,涵盖了技术框架设计,发布流程,多语言等内容。并且对于大部分海外地区来说,Android 机型分布比较混乱,低端机型较多,且网络环境较国内比较差。在启动速度,内存管理、网络优化等方面,我们出海的 APP 还有很多需要建设的地方,希望能和大家进行分享交流。

恭喜郭士强,最新职位曝光,姚明没看错人,周琦伤病出现新情况还有一个星期,CBA第二阶段的比赛就要正式开始了。在这之前将会在12月3日,也就是后天补办上个赛季的全明星。届时CBA最优秀的篮球运动员将会为球迷带来一场精彩纷呈的表演赛。其实第二我国首个千万千瓦级多能互补综合能源基地新能源项目开启全面建设原标题我国首个千万千瓦级多能互补综合能源基地新能源项目进入全面建设阶段11月30日,陇电入鲁配套华能庆阳600万千瓦新能源示范项目首台风机成功吊装,这标志着我国首个千万千瓦级多能互江苏省南京市12月最新一批建设工程项目清单来了,含具体投资额2022年第四季度南京市重大工程和重点项目49个,总投资202。2066亿元,年度计划投资202。2066亿元(其中19个项目列为省重大工程和重点项目,总投资103。0726亿元,中超最新积分榜泰山队输球,三镇也输球,好兄弟,要一起掉队?中超联赛到了飙演技的时候了,如果输球,就一定要演的好一些。泰山队先是2比3输沧州雄狮,球迷心里想,没冠军了。武汉三镇对亚泰的比赛,武汉三镇最后靠自己的乌龙球,完成输球,看起来两支球国际最新研究黑洞瓦解恒星引发天文奇观或助理解黑洞特性中新网北京12月1日电(记者孙自法)国际著名学术期刊自然和专业学术期刊自然天文学最新分别发表论文称,研究人员报道了一次罕见潮汐瓦解事件(TDE,指当一颗恒星被一颗特大质量黑洞撕裂时球王贝利因全身肿胀入院治疗,女儿证实无生命危险极目新闻记者李力力据ESPN报道,当地时间周三,巴西足球传奇贝利因全身肿胀入院治疗。贝利的女儿凯莉纳西门托随后在社交媒体上表示,父亲没有生命危险。贝利(图片来源BBC)据悉,贝利已人工智能,机器的生命体征和摩尔定律在生命出现之前,整个宇宙中只充斥着无机物简单的有机物元素颗粒等简单物质,似乎毫无生机。在生命出现之后,复杂物质开始陆续出现。科学家在外太空探索生命的过程中,以寻找复杂物质作为探寻生湖南这么冷,为何超5千只小天鹅还来此过冬?专家解答多个冷知识小天鹅长大后就是大天鹅吗?小天鹅为什么来湖南这么冷的地方这里过冬?从西伯利亚飞到湖南要多久湖南气温骤降,但在岳阳屈原管理区东古湖湿地,仍在上演天鹅湖5000多只从西伯利亚远道而来小坠落在地球上的天外来客,带来了有关生命的线索2021年2月28日晚10点左右,一颗火球在英格兰上空划过。超过千人看到了这颗炽热的天外访客,许多追踪摄像机以及民用监控设备都拍摄了它的降落过程。第二天早上的新闻开始提醒温什科姆以明日方舟哪些冷知识是老玩家才知道的,浮士德的紫箭是物伤大家好,我是戒戒,专注于分享游戏心得和趣事的戒戒不知不觉中明日方舟这款经典的二次元塔防手游已经公测上线运营三年多了,在三年的时间里罗德岛的队伍成员也越来越多,队伍不断壮大的同时,罗考虑到让老滚6玩10到20年B社改变了其设计方式近日,B社的游戏总监托德霍华德在节目中提到上古卷轴6时表示,他们也希望游戏能快点出。我希望它很快,我们也希望它能发布。希望他们不要花那么长时间如果我能回到过去,我的计划肯定不是让它
杨幂皮裤配球鞋火上热搜!都在问粉毛兔兔装是什么来头!最近杨幂上身一件粉色毛绒兔子外套火上热搜,可爱的毛绒装扮和醒目兔尾点缀,在寒冷冬季散发出温暖俏皮的时尚气氛。杨幂可爱兔子装火上热搜在网络疯狂刷屏的同时,袖子上出现的小剪刀Logo也在冬天,没有人能逃过针织的温柔冬日生活打卡季无论冬天冷不冷,一件有质感的针织总是衣橱必备,除了穿岀时尚感,也为事事讲求效率的当代丽人提供着轻松快捷的打扮方法,因此以这一单品为中心的造型也格外丰富多彩。柔软又亲肤3000元价位究竟哪款手机值得买?2K骁龙8Gen2,能否制霸中端市场这时间一到年度,就突然有了想给自己换台新机的想法。不过受限于预算的压力,我确实没办法去现在市面上的那些旗舰机型,只能退而求其次选择3000元左右价位的中高端机型。而在中端手机市场当2499元起!RedmiK60系列正式发布,2K屏幕30W无线充电RedmiK60系列正式发布,全系共计三款手机分别搭载三颗高口碑处理器,新机在屏幕质感影像性能等维度都有升级,主打旗舰机焊门员。RedmiK60正面搭载6。67英寸OLED柔性直屏RedmiK60系列发布骁龙8Gen2120W5000mAh,2199元起售K50宇宙发布的时候让我很惊讶,没想到这一次K60更加的强,无论是处理器屏幕影像续航几乎没有短板,看得出来这次卢伟冰的准备还是比较充足的,那么今天就和大家一起来聊一聊这个系列手机。4nm旗舰芯12GB512G66W,仅3599元,vivo新款手机价格亲民许多网友都喜欢在年底购买手机,因为这个时间点,一方面可以买到新款手机,另外一方面,我们也可以用更亲民的价格买到某些大降价的老旗舰。如果你是vivo的粉丝,习惯了vivo手机的生态,骁龙8Gen2手机推荐一加11努比亚Z50摩托罗拉X40你更喜欢谁眼看就要到年末新年了,对于想要购买新款手机的小伙伴们而言,目前智能手机市场可以选择的旗舰产品真的太多了,但是对于追求高性能的小伙伴而言,搭载骁龙8Gen2的旗舰手机显然会是优先考虑华为P60系列保护壳曝光三摄像头布局奇特,新机或明年3月发布Tech星球12月27日消息,今日网上流出了疑似是华为P60系列的手机壳,图片显示该机采用了非常独特的三摄布局。据悉,该图片来自博主数码闲聊站,图片显示该机的后置摄像头位于左上角,怎样的折叠屏手机能让人爱不释手?我在FindN2上有了答案随着各大手机厂商纷纷入局折叠屏市场,现在市面上的折叠屏手机已经有了不少选择,并且也有越来越多的用户用上了折叠屏。很多人认为折叠屏幕手机和直板手机在体验上差不多,毕竟都是手机,无非就荣耀80GT手机怎么样?除了性价比高,还有哪些优点?荣耀80GT手机怎么样?除了性价比高,还有哪些优点?备受关注的荣耀80GT手机已经在26日的晚上正式发布,这款智能手机的优势就是性价比相对较高,定位中低端系列品牌,除了性价比相对较总投资198亿!交椅湾大开发提速!刚刚,交椅湾半岛两宗工业用地,以底价6。19亿元成交。拍得地块的,正是东莞市欧珀通信科技有限公司。这也意味着,OPPO芯片研发中心项目,正式落户交椅湾。该项目总投资超过45亿元,且