
通过上图可以看出整体的业务流程是:游戏调用proxy的代理接口→代理接口调用具体集成的渠道api,这样无论底层的渠道如何变换,只要代理层的接口设计能覆盖渠道所有的能力,那么对于上层游戏来说渠道的变化就是无感知的,这样做到了游戏和渠道的彻底解耦,也做到了渠道的整合。
整个流程中大部分的工作调用apktool的api就能够实现,但是如何去替换注入渠道sdk的代码呢?熟悉逆向的同学一定知道,apktool反编译之后生成的是smali文件,大概长成下面这样:
别说修改了,这种类似汇编的代码的可读性都很差。换一种思路,如果我们编辑的是java文件,那是不是就方便很多了。顺着这种思路,如果我们有一个集成了渠道sdk的demo.apk,再提供给CP一个代理sdk,通过apktool反编译demo.apk之后生成的smali文件替换母包反编译后对应的代理类,这样就可以实现渠道代码的注入了。同样,我们只要针对每个渠道单独开发一个接入的demo.apk就可以复用在所有的游戏上。这样既做到了渠道的独立,又可以横向扩展。因此,我们设计了一套代理层,对上暴露登录,支付,鉴权等基础能力的api,内部是渠道api的调用,基于这套代码打包出来的就是demo.apk了。
其次,渠道之间还有很多差异化的内容要处理,最简单就是同一个游戏不同的渠道包名是不一样的。这里就要用到反编译之后的yml文件了,这个文件记录了反编译的配置信息,用于回编译的时候读取,用修改包名举例,只要增加第一行的配置就可以改变回编译之后的包名了。
同时,yml文件还可以自定义很多配置,这里就不展开了,感兴趣的同学可以自行了解一下。最后,解决了代码合并,渠道差异化的配置之后,整个打包过程大致为以下几步:1. 准备游戏母包和对应的渠道demo.apk2. 通过apktool d xxx命令分别反编译这两个apk,得到如下文件结构
3. 合并AndroidManifest.xml,合并assets中的文件,合并lib,合并并替换res中的相应资源和配置文件,替换smali中的相关文件4. 通过apktool b xxx命令回编译apk5. 通过签名工具对回编译的apk进行签名
至此,我们就可以把繁琐的人工打包过程转换成简单的脚本命令来实现,节省时间的同时还能保证准确率。
我们通过解析game和sdk的public.xml文件,然后用sdk里的资源和game进行对比:1. 如果sdk内的资源game里没有,把资源保存到新增资源集合A中2. 如果sdk中有game里一样的资源,我们会保留game里的id,并且记录sdk的新旧id映射保存到集合B中3. 合并的时候会先去读集合A中的id,判断是否有冲突,如果和现有id冲突了,会通过一定的规则重新生成id,并且也和步骤2一样,把新旧id的映射保存到集合B中4. 读取集合B,全量搜索旧id的值,替换成新id5. 生成新的public.xml
大致方法如上所示,一些细节的实现就不占用篇幅赘述了,至此,资源文件相关的处理就完成了。
其中authorities是唯一标识,渠道sdk中ContentProvider的authorities都会使用包名+类名的方式来声明
这样对于集成了渠道sdk的demo.apk来说,所有ContentProvider的authorities都是相同的,这就会导致如果单渠道多个游戏,当第二个游戏安装的时候就会由于authorities冲突导致失败,因此我们首先需要用特殊的占位符替换包名字段,然后再manifest合并的时候识别占位符,用渠道子包的包名来替换。
当然,如果这么简单就能处理完,就不会出现在”避坑建议“里了,其实很多渠道的ContentProvider声明是放在自己sdk的manifest里的,对于这样的渠道,我们需要在集成渠道sdk工程里的manifest进行authorities替换,需要使用replace,这样在渠道demo打包的时候,manifest合并过程中就会把渠道sdk内部的authorities改成我们自定义的authorities。
最后,同样的问题还会出现在permission中,有一些渠道sdk中声明了自定义的permission来限制对自己服务或者是组件的调用,处理这部分问题的方法和provider类似,这里就不赘述了。
整个打包平台的方案,解决了之前出包流程上耗时的点:1. 包体多次传输打包平台将原来的上传→下载→上传的三次传输过程简化成了单次上传。2. 人工响应时间工作时间响应时间是比较稳定的,但是当出现突发情况,很有可能会有非工作时间(午夜、假日)的打包需求,这时候可能由于各种原因技术无法及时出包,通过平台出包可以避免此类的响应问题。3. 加固流程现在加固基本是每个app必备的流程,有一部分游戏加固是在签名前对每一个渠道包进行一次加固,然而目前我们加固是采用第三方的解决方案,基于这种情况就会中断我们的打包流程,在签名前还需要给第三方进行一次加固,然后再签名,并且这样也会造成多次的游戏包上传下载的操作,严重影响出包效率,也增加了很多人工操作的工作量。为了进一步提升打包体验和效率,我们整合了部分加固方案,让加固变成了打包流程的一个部分,流程对比如下:
从上图可以看到通过平台集成了加固流程后,每个包额外又减少了6次传输,以及一系列的人工操作,对于打包的时间和体验有非常大的提升。6.2 耗时对比游戏包不同于别的app,单个游戏都在1-2G不等,单次传输的耗时也在3-5分钟,如果是外网环境速度会更慢,优化了两次传输流程后,整体出包流程提升6-10分钟/个包,平均每个游戏接入的渠道有8-10家,相当于每次出包缩短了一个小时的耗时。对于加固包而言,平时整个流程可能需要1-2个小时,中间由于上传、加固等多方响应时间,可能会更长,但是通过系统只需要十几分钟就能完成所有渠道的出包。
我们用重生细胞做了一次测试,8个渠道整个打包、加固、签名一共只用了20分钟都不到,其中耗时的还是加固流程,可以看到下面无需加固的bangGream 7个渠道只用了3分钟。很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin
如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
我有一个使用Qt4绑定(bind)的Ruby应用程序。我希望能够打包并发布它。我查看了其他应用程序,例如rake和puppet,以了解它们是如何打包的。rake和puppet都被打包为gems。当我意识到rake和puppet都是更多的系统级工具而不是用户级应用程序时,我开始走这条路。我也看过orca,但它只是windows。除了gem或orca,是否还有其他选项可用于打包RubyGUI应用程序?我想要跨平台的东西。 最佳答案 看看platformgem规范。您可以为您的代码支持的每个平台打包一个gem。Somegemsconsis
我正在使用Devise在Rails应用程序中,并希望通过API公开一些模型数据,但应该像应用程序一样限制对API的访问。$curlhttp://myapp.com/api/v1/sales/7.json{"error":"Youneedtosigninorsignupbeforecontinuing."}很明显。在这种情况下是否有访问API的最佳实践?我更喜欢一步验证+获取数据,但这只是为了让客户的工作更轻松。他们将使用JQuery在客户端提取数据。感谢您提供任何信息!凡妮莎 最佳答案 我建议您按照以下帖子中的选项2:使用APIke