GooglePlay - 文件上传限制的扩展

前言

  Google Play应用商店在上传限制100MB大小,超过该大小的应用必须将超过部分以扩展文件的形式进行上传处理。 总共可上传2个扩展文件,每个最大文件可为2GB,同时obb文件格式可自选。

官网地址:http://developer.android.com/google/play/expansion-files.html

 

准备

  1、在sdk Manager中下载对应的支持库,play_licensing及play_apk_expansion如下:

    

  2、生成需要的obb文件,并在上传apk包的同时选择上传扩展文件。

    obb文件生成可参考jobb工具生成(官网推荐), http://developer.android.com/tools/help/jobb.html

    也可以直接用参考stackoverflow上Sanket Kachhela的回答(个人推荐):http://stackoverflow.com/questions/14495483/read-content-from-apk-expansion-file-from-obb-file#answer-18953778,直接利用zip压缩工具选择存储模式。

  3、如果上述采用zip压缩的话,这里就还需要unzip准备,利用zipHelper直接解压下载包并正常使用。

    参考stackoverflow上Bhavesh Hirpara的回答:http://stackoverflow.com/questions/14495483/read-content-from-apk-expansion-file-from-obb-file#answer-15150977

  

链接库配置

  1、在eclipse打开需要的库工程,如下:

    

  2、如果downloader_library出现错误 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解压出来的文件了。

 

posted @ 2016-02-23 11:40  稀饭lei___  阅读(5699)  评论(0编辑  收藏  举报