在游戏快上线的时候,我们除了接入多家联运的渠道SDK之外,还有另一些情况存在。就是常说的CPS,CPA,CPD等情况。这些都无需接入SDK,仅仅是一些广告推广手段。通常我们会基于官方SDK的游戏包,生成多个用逻辑渠道号标识的一些包。用这些逻辑渠道号来标示这个游戏包属于哪个广告渠道。
通常就是这样的需求,比如:基于官方SDK的包生成以下逻辑渠道包:
google渠道包
友盟渠道包
百度推广渠道包
……
这些渠道包,我们需要的唯一区别就是标识其属于哪个渠道即刻。所以,通常我们只需要在游戏里面增加一个渠道号的标识。那么,现在需求就来了。在u8sdk中,我们怎么快速的生成这样的渠道包呢?
当然,按照目前的u8sdk打包脚本已经可以实现这样的工作了。但是,一般这样的逻辑渠道包动不动就是上百个,如果严格按照拆包,修改渠道号,重新打包,签名这样的步骤,那么几百个渠道包生成下来,估计至少得好几个小时的时间。
现在的问题就是可不可以在不拆包的情况下,直接修改原包,把里面的渠道号给改变一下。答案是可以的。apk包本质上还是一个zip压缩包,只是这个压缩包是经过严格签名的。那么,我们是否可以解压这个压缩包,然后改里面的某个文件呢?话说这样的文件真不好找。因为你改变了某个文件之后,这个包就得重新签名。
好在,方法还是有的,那就是“在apk的签名目录下也就是META-INF/目录下建立新的空文件,不需要对apk重新签名”
有了这个方法,就不再需要对APK进行重新签名,速度还是相当快的。几百个包,一两分钟即可处理完毕!!!
那么现在的思路就简单清晰了,我们只需要通过zip在META-INF/目录下建立一个以渠道号为名称的空文件,然后在u8sdk抽象层的代码里面通过读取该空文件的文件名就可以得到当前的逻辑渠道号。
下面我们就看怎么在U8SDK中实现这样的功能。
首先我们需要一个配置,来配置需要所有渠道号。然后需要一个已经接入了官方SDK的游戏包(apk文件)。接着便可以写脚本了。我们定义一个modify_channels.py脚本:
# -*- coding: utf-8 -*-
#CreateTime:2014-10-25
importsys
importfile_operate
importos
importos.path
importtime
importzipfile
defentry():
sourceApkFile=file_operate.getFullPath("u8source.apk")
channelsFile=file_operate.getFullPath("channels.txt")
ifnotos.path.exists(channelsFile):
file_operate.printF("The channels.txt file is not exists.")
return
f=open(channelsFile)
channelLines=f.readlines()
f.close()
channels=[]
ifchannelLines !=Noneand len(channelLines) >0:
forlineinchannelLines:
targetChannel=line.strip()
channels.append(targetChannel)
else:
file_operate.printF("There is no channel configed in channels.txt")
modify(channels, sourceApkFile)
defmodify(channels, sourceApkFile):
sourceApkFile=sourceApkFile.replace('\\', '/')
ifnotos.path.exists(sourceApkFile):
file_operate.printF("The source apk file is not exists")
return
tempFolder=file_operate.getFullPath('temp')
ifnotos.path.exists(tempFolder):
os.makedirs(tempFolder)
empty_file=os.path.join(tempFolder, "temp.txt")
f=open(empty_file,'w')
f.close()
forchannelinchannels:
generateNewChannelApk(sourceApkFile, empty_file, channel)
file_operate.del_file_folder(tempFolder)
defgenerateNewChannelApk(sourceApkFile, empty_file, channelID):
file_operate.printF("Now to generate channel %s", channelID)
targetFolder=file_operate.getFullPath("channels")
ifnotos.path.exists(targetFolder):
os.makedirs(targetFolder)
targetApk=os.path.join(targetFolder, "u8-"+channelID+".apk")
file_operate.copy_file(sourceApkFile, targetApk)
zipped=zipfile.ZipFile(targetApk, 'a', zipfile.ZIP_DEFLATED)
emptyChannelFile="META-INF/u8channel_{channel}".format(channel=channelID)
zipped.write(empty_file, emptyChannelFile)
zipped.close()
entry()
这个脚本有几点说明:
1、游戏包名必须是u8source.apk。当然你可以可以修改成其他的
2、渠道号的配置文件必须是channels.txt,并且是每行配置一个渠道号
3、脚本会创建一个临时的temp目录下的temp.txt空文件,然后将这个空文件添加到META-INF/目录下,并以u8channel_{渠道号}进行命名
4、所有包打完之后,会删除temp目录
5、所有最终的包会输出到channels目录下,并以u8-{渠道号}.apk进行命名
紧接着我们需要在u8sdk的抽象层逻辑里,来读取apk目录下的META-INF/目录下的以u8channel_开头的文件,从而获取到逻辑渠道号。
/**
* 获取CPS,CPA,CPD等非SDK联运渠道的逻辑渠道号
* @return
*/
publicintgetLogicChannel (){
if(this. channel >0){
returnthis. channel;
}
String chStr = SDKTools. getLogicChannel(application, LOGIC_CHANNEL_PREFIX);
if(!TextUtils. isEmpty(chStr)){
this. channel = Integer. valueOf(chStr);
}else{
this. channel =0;
}
returnthis. channel;
}