前言
Google Play应用商店在上传限制100MB大小,超过该大小的应用必须将超过部分以扩展文件的形式进行上传处理。 总共可上传2个扩展文件,每个最大文件可为2GB,同时obb文件格式可自选。
准备
1、在sdk Manager中下载对应的支持库,play_licensing及play_apk_expansion如下:
2、生成需要的obb文件,并在上传apk包的同时选择上传扩展文件。
链接库配置
1、在eclipse打开需要的库工程,如下:
AESObfuscator cannot be resolved 则说明Eclipse没有选择自动编辑,勾选下project->build automatically即可。
3、添加游戏项目,并添加对应的依赖项目如下图:
项目配置
1、添加对应的权限。
<manifest ...>
<!-- Required to access Google Play Licensing -->
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
<!-- Required to download files from Google Play -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Required to keep CPU alive while downloading files
(NOT to keep screen awake) -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Required to poll the state of the network connection
and respond to changes -->
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Required to check whether Wi-Fi is enabled -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- Required to read and write the expansion files on shared storage -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
2、从~sdk\play_apk_expansion\downloader_sample项目复制src\com\example\expansion\downloader下的sample文件到游戏目录下,并对应修改包名的引用等。
a、将onCreate下的判断obb文件存在的注释处理添加如下:
// otherwise, download not needed so we fall through to
// starting the movie
validateXAPKZipFiles();
b、修改 validateXAPKZipFiles 方法,去除验证,直接添加解压方法到对应的游戏下载目录。
// 解压到游戏下载目录
private void upzipApkExFile(){
try {
ZipResourceFile expansionFile = APKExpansionSupport
.getAPKExpansionZipFile(this, VERSION_CODE, 0);
ZipEntryRO[] zip = expansionFile.getAllEntries();
Log.i("upzipApkExFile", "mZipFileName : " + zip[0].mZipFileName);
String path = getApplicationContext().getFilesDir().getAbsolutePath();
File file = new File(path + "");
ZipHelper.unzip(zip[0].mZipFileName, file);
if (file.exists()) {
Log.e("", "unzipped : " + file.getAbsolutePath());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Go through each of the Expansion APK files and open each as a zip file.
* Calculate the CRC for each file and return false if any fail to match.
*
* @return true if XAPKZipFile is successful
*/
void validateXAPKZipFiles() {
upzipApkExFile();
Intent myIntent = new Intent(this, AppActivity.class); //跳转到游戏Activity
startActivity(myIntent);
this.finish();
}
c、修改SampleDownloaderService文件下的BASE64_PUBLIC_KEY。将其改成对应的Google Play上申请的应用的Key。
3、添加对应下载接受服务监听。
<application ...>
<service android:name="com.test123.expansion.downloader.SampleDownloaderService" />
<receiver android:name="com.test123.expansion.downloader.SampleAlarmReceiver" />
...
</application>
4、主游戏AppActivity处理。在启动的Activity中进行判断,如果已经下载并解压了文件则进入游戏,否则跳转到下载的Activity。
protected void onCreate(final Bundle savedInstanceState){
super.onCreate(savedInstanceState);
String path = getApplicationContext().getFilesDir().getAbsolutePath();
File boolfile = new File(path + "/downloaded");
if(!boolfile.exists())
{
Intent myIntent = new Intent(this, SampleDownloaderActivity.class);
startActivity(myIntent);
this.finish();
return;
}
Log.i("upzipApkExFile", "already unziped!!");
}
Cocos2dx处理
为了让下载的扩展文件直接应用到游戏中,我们要稍微修改下cocos2dx引擎的读取文件处理。
首先,找到引擎目录下cocos2d\cocos\platform\CCFileUtils.cpp文件。
其次,对方法进行如下修改,使其先在getWritablePath目录下需找文件。
std::string FileUtils::fullPathForFilename(const std::string &filename) const
{
if (filename.empty())
{
return "";
}
if (isAbsolutePath(filename))
{
return filename;
}
// Already Cached ?
auto cacheIter = _fullPathCache.find(filename);
if(cacheIter != _fullPathCache.end())
{
return cacheIter->second;
}
// Get the new file name.
const std::string newFilename( getNewFilename(filename) );
std::string fullpathWritablePath = getWritablePath() + newFilename;
if (isFileExistInternal(fullpathWritablePath))
{
if (fullpathWritablePath.length() > 0)
{
// Using the filename passed in as key.
//_fullPathCache.insert(std::make_pair(filename, fullpathWritablePath));
_fullPathCache[filename] = fullpathWritablePath;
return fullpathWritablePath;
}
}
std::string fullpath;
for (const auto& searchIt : _searchPathArray)
{
for (const auto& resolutionIt : _searchResolutionsOrderArray)
{
fullpath = this->getPathForFilename(newFilename, resolutionIt, searchIt);
if (fullpath.length() > 0)
{
// Using the filename passed in as key.
_fullPathCache.insert(std::make_pair(filename, fullpath));
return fullpath;
}
}
}
if(isPopupNotify()){
CCLOG("cocos2d: fullPathForFilename: No file found at %s. Possible missing file.", filename.c_str());
}
// The file wasn't found, return empty string.
return "";
}
而这里getWritablePath获取的目录正是我们之前解压obb文件的目录getApplicationContext().getFilesDir().getAbsolutePath()。
因此,到这里就可以在游戏中跟使用在assert中文件一样使用obb解压出来的文件了。