Appearance
自定义脚本
IMPORTANT
秉着游戏和SDK开发完全解耦的思想,遇到某些渠道SDK的特殊要求,可能需要和游戏耦合的,尽可能通过自定义脚本完成,而不要直接写死。
为了让打包工具更加灵活好用,我们给每个渠道SDK或者插件SDK配置目录下安插了一个自定义脚本。其中渠道SDK目录下叫sdk_script.py;插件目录下叫script.py。当然,他们都是可选的,只有在需要用到的时候,你才需要。
同时,游戏级别也支持自定义脚本, 附加对全渠道适用的通用自定义逻辑。
举几个例子:
1、将AndroidManifest.xml中${applicationId}替换为最终的包名
2、将游戏的Application设置为XXXApplication
3、WXEntryActivity需要放在游戏包名+.wxapi包名路径下
4、在AndroidManifest.xml中添加或者修改一个meta-data的值
5、游戏打包时,希望将AndroidManifest.xml中一个meta-data设置为当前渠道名称,全渠道生效
......
除了上面这些情况,只要是apk里面的东西, 我们都能够通过自定义脚本来完成添加,修改,删除等操作。自定义脚本,在打包过程中回编译之前执行。
脚本定义
之前在渠道SDK接入的配置中,我们说过,每个渠道SDK接好之后,都配置到打包工具的config/sdk目录下。
如果当前渠道有需要执行特殊的逻辑,需要执行一段自定义脚本,那么在该渠道的配置目录下新建一个sdk_script.py文件,内容如下:
py
import os
import os.path
from xml.etree import ElementTree as ET
from xml.etree.ElementTree import SubElement
from xml.etree.ElementTree import Element
from xml.etree.ElementTree import ElementTree
import os
import os.path
import zipfile
import re
import subprocess
import platform
from xml.dom import minidom
import codecs
import sys
import sdk_helper
import file_utils
androidNS = 'http://schemas.android.com/apk/res/android'
def execute(channel, decompileDir, packageName):
//这里写自定义逻辑
1、脚本入口函数固定,是execute。含有三个参数
2、channel:渠道对象,里面有当前渠道的参数等数据
3、decompileDir:当前渠道的工作目录
4、pacakageName:最终的包名
如果是插件目录,那么新建一个script.py,对应里面的接口是:
py
import os
import os.path
from xml.etree import ElementTree as ET
from xml.etree.ElementTree import SubElement
from xml.etree.ElementTree import Element
from xml.etree.ElementTree import ElementTree
import os
import os.path
import zipfile
import re
import subprocess
import platform
from xml.dom import minidom
import codecs
import sys
import sdk_helper
import file_utils
androidNS = 'http://schemas.android.com/apk/res/android'
def execute(channel, pluginInfo, decompileDir, packageName):
//这里写自定义逻辑
脚本实例1
1、场景
SDK的Manifest配置中, 有一个provider,需要将里面的android:authorities设置为[最终包名.FileProvider]
2、解决方案
我们在SDKManfiest.xml中,先将需要设置为最终包名的地方, 用${applicationId}替换:
xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
3、代码片段
py
def execute(channel, decompileDir, packageName):
manifestFile = decompileDir + "/AndroidManifest.xml"
file_utils.modifyFileContent(manifest, "${applicationId}", packageName)
return 0
脚本示例2
1、场景
某渠道SDK,要求游戏中Application必须设置为他们的com.xxx.sdk.XApplication。
2、解决方案
因为java是单继承,U8SDK中已经要求游戏的Application设置为或者继承com.u8.sdk.U8Application
。 所以我们可以通过自定义脚本,完成application的继承关系转换。 U8SDK脚本中已经提供了对应的函数调用,可以一键完成接入。
3、代码片段
py
def execute(channel, decompileDir, packageName):
sdk_helper.modifyRootApplicationExtends(decompileDir, 'com.xxx.sdk.XApplication')
return 0
脚本实例3
1、场景
360渠道SDK,如果要使用微信功能,我们需要将WXEntryActivity.java放到{packageName}+".wxapi"包名下面。
2、解决方案
因为最终的包名是游戏包名加上当前渠道后缀来的,所以我们不可能直接将该类放在对应的包名路径下,然后编译生成jar包。这样其他的游戏就无法使用该渠道SDK对应的功能了。
所以,我们还是通过自定义脚本来完成这个工作。
1、在SDKManifest.xml中配置好WXEntryActivity
2、在该渠道的配置目录下新建一个extraFiles子目录,然后将360SDK.jar和WXEntryActivity.java拷贝到这个文件中
3、编写自定义脚本,重新编译WXEntryActivity.java,生成smali合并到最终的包名+".wxapi"路径下
3、代码片段
py
def execute(channel, decompileDir, packageName):
sdk_helper.compileJava2Smali(channel, decompileDir, packageName+".wxapi", 'EntryActivity', ["360SDK.jar"])
return 0
脚本实例4
1、场景
友盟统计插件,需要在AndroidManfeist.xml中配置一个UMENG_CHANNEL,这个值每个渠道都不同,后台根据这个渠道来区分来源
2、解决方案
因为这个值是每个渠道都不同的,所以,我们不可能每个渠道打包的时候,手动来设置。所以,最好的版本,就是通过自定义脚本来实现。 解决方案的思路是:我们在插件config.xml中的param中定义一个key为UMENG_CHANNEL的参数,然后通过自定义脚本,将这个参数的值,设置为当前渠道的名称
3、代码片段
py
def execute(channel, pluginInfo, decompileDir, packageName):
channel = sdk_helper.getSdkParamByKey(channel, 'UMENG_CHANNEL')
sdk_helper.addOrUpdateMetaData(decompileDir, 'UMENG_CHANNEL', channel)
脚本实例5
1、场景
游戏打包时,希望将AndroidManifest.xml中一个meta-data(name是GAME_CHANNEL_NAME)设置为当前渠道名称,全渠道生效。
2、解决方案
因为这个值是全渠道都需要设置的, 我们无法将这个逻辑写在各个渠道的sdk_script.py中。 此时,最好的方案是将该逻辑添加到游戏级别的自定义脚本。 解决方案的思路是:在打包工具->游戏扩展参数配置面板,设置游戏级别的自定义脚本post_script.py,在里面读取当前渠道名称,并设置到meta-data中。
3、代码片段
py
def execute(channel, pluginInfo, decompileDir, packageName):
sdk_helper.addOrUpdateMetaData(decompileDir, 'GAME_CHANNEL_NAME', channel['name'])