Google Play渠道超過(guò)100M铛铁?嘗試APK分包隔显!

前言

  • 一般情況下,Android開(kāi)發(fā)者應(yīng)該通過(guò)各種有效途徑來(lái)減小生成的Apk大小饵逐,比如移除無(wú)效資源文件括眠、只保留xxhdpi資源、離線懶加載非必要資源等倍权。
  • 特殊情況下掷豺,出于對(duì)用戶(hù)體驗(yàn)的考慮,一些依賴(lài)高清無(wú)損資源的App可能會(huì)生成幾百M(fèi)甚至1G以上的安裝包薄声,國(guó)內(nèi)的分發(fā)平臺(tái)對(duì)安裝包的大小沒(méi)有強(qiáng)制規(guī)定当船,但是對(duì)于出海產(chǎn)品來(lái)說(shuō),Google Play并不允許開(kāi)發(fā)者上傳超過(guò)100M的安裝包默辨。
  • 針對(duì)以上問(wèn)題德频,Google官方提供了Apk Expansion Files,支持開(kāi)發(fā)者構(gòu)建超過(guò)100M的安裝包缩幸。

概念

  • 首先壹置,對(duì)于傳統(tǒng)的Android開(kāi)發(fā)領(lǐng)域來(lái)說(shuō),分包指的是MultiDex表谊,即將單個(gè)dex拆分成多個(gè)以突破函數(shù)數(shù)目瓶頸的技術(shù)钞护。而這里的分包(Apk Expansion Files)指的是將Apk文件和大容量的資源文件分開(kāi)打包,大容量的資源文件包括高清大圖爆办,音頻文件难咕,視頻文件等,這些文件最終都會(huì)壓縮到統(tǒng)一的.obb文件里。注意步藕,抽出到obb的內(nèi)容不包括運(yùn)行時(shí)代碼惦界。所以開(kāi)發(fā)者需要保證在缺少.obb文件的情況下挑格,程序依然能正常運(yùn)行(不會(huì)Crash)咙冗。

  • 在分包之前,開(kāi)發(fā)者需要明確項(xiàng)目中的大容量資源文件究竟是什么漂彤,大多數(shù)情況下雾消,他們指的是assets目錄下的資源以及raw下的文件,如果drawablemipmap目錄下有超過(guò)1M的文件挫望,也可以考慮將其進(jìn)行分包處理立润,這種情況下需要開(kāi)發(fā)者將該資源的引用方式從直接使用資源id:R.drawable.xxx改為從文件中解析。

  • 所有的資源文件將被壓縮為obb文件媳板,最終上傳到GooglePlay供用戶(hù)下載桑腮。

obb文件

  • 概念

    什么是obb文件,obb全稱(chēng)是Opaque Binary Blob蛉幸,翻譯過(guò)來(lái)是不透明的二進(jìn)制對(duì)象破讨,再進(jìn)一步解析就是具有訪問(wèn)權(quán)限的二進(jìn)制文件∞热遥看到這個(gè)定義很容易聯(lián)想到另外一種文件格式——zip壓縮包文件提陶。所以,從本質(zhì)上來(lái)說(shuō)匹层,obb文件和zip文件是一樣的隙笆,它們只是在不同領(lǐng)域上不同解釋罷了。而在Android分包領(lǐng)域升筏,obb還有自己的一些規(guī)則撑柔。

  • 命名規(guī)則

    obb的命名規(guī)則如下:

    [main/patch].[versionCode].[packageName].obb
    
    • 第一部分由可選字段組成,只能填入main或者patch您访,main指的是主擴(kuò)展文件铅忿,而patch是對(duì)于main的補(bǔ)丁或擴(kuò)展。第一次分包時(shí)填入main洋只,而后續(xù)如果只是對(duì)分包進(jìn)行增量修改的話辆沦,填入patch。筆者習(xí)慣每次發(fā)版都將所有資源重新打包成obb文件识虚,所以只使用main字段肢扯。
    • 第二部分為當(dāng)前app的 versionCode,當(dāng)確定好這次發(fā)版的versionCode后担锤,大膽填入即可蔚晨。
    • 第三部分為 packageName,可在AndroidManifest.xml的根節(jié)點(diǎn)中讀取package字段得到。
    • 最后記得加上obb文件后綴名铭腕。
    • 這里舉個(gè)例子:
    main.16.com.example.obbtest.obb
    
  • 生成方法

    • 方法一:

      官方工具法银择,Google官方提供了Jobb工具用來(lái)生成obb文件,工具可以在 Android\sdk\tools\bin文件夾下找到累舷。這是一個(gè)命令行工具浩考,具體用法和參數(shù)如下:

      $ jobb -d [所有資源的路徑] -o [生成的obb名稱(chēng)(請(qǐng)遵循上述命名規(guī)則)] -k [打包密碼] -pn [包名] -pv [versionCode(跟obb名稱(chēng)的versionCode一致)]
      

      也可以使用該工具對(duì)obb文件進(jìn)行解壓:

      $  jobb -d [輸出路徑] -o [obb文件名] -k [打包所用的密碼]
      
    • 方法二:

      壓縮工具法,直接使用Windows或者M(jìn)ac上的打包工具被盈,將文件壓縮成zip包后析孽,更改文件名即可。


      壓縮工具法

      需要注意的是只怎,壓縮文件格式需要選擇zip袜瞬,并將壓縮方式改為存儲(chǔ)。如需進(jìn)行加密身堡,可使用壓縮工具自帶的設(shè)置密碼方法邓尤,得到的效果和官方方法設(shè)置 -k 參數(shù)是一樣的。
      壓縮完后別忘了將文件名改為符合命名規(guī)范的obb文件名贴谎,如:

      main.16.com.example.obbtest.obb
      
    • 方法三:

      gradle打包法汞扎,即通過(guò)在build.gradle中添加壓縮腳本的方式,將需要打入obb的資源集體打包的方法赴精。該方法會(huì)在后文中進(jìn)行詳細(xì)介紹佩捞。

上傳obb測(cè)試

  • 本地測(cè)試
    本地測(cè)試的原理是模仿Google Play下載,將obb文件復(fù)制到相應(yīng)的目錄蕾哟。通過(guò)Google Play下載的obb文件存放的路徑為:

    /Android/obb/App包名/
    

    所以一忱,通過(guò)在/Android/obb/下創(chuàng)建[app包名 如com.example.obbtest]文件夾,并將obb文件復(fù)制到該目錄下即可模擬Google Play安裝App谭确。

  • 線上測(cè)試

    • 登錄Google Play Console開(kāi)發(fā)者賬號(hào)帘营,打開(kāi)應(yīng)用列表,選擇需要測(cè)試的App:

    • 左邊控制欄選擇 Release managerment 逐哈,然后選擇 App Release芬迄,最后選擇Internal testMANAGE INTERNAL TEST發(fā)布內(nèi)部測(cè)試版本。

      image
    • 在內(nèi)部測(cè)試?yán)飫?chuàng)建新的發(fā)布版本:將GooglePlay版本的Apk上傳昂秃,上傳完畢后禀梳,點(diǎn)擊Apk右側(cè)添加更多按鈕,將obb文件提交上去肠骆,注意obb文件的命名版本號(hào)必須與上傳的apk的版本號(hào)一致算途,否則會(huì)收到提交版本失敗的錯(cuò)誤。推薦大家使用不可能用在線上版本的versionCode進(jìn)行測(cè)試蚀腿,比如手機(jī)號(hào)碼嘴瓤、女朋友生日等,以免后續(xù)提交正式版本時(shí)版本號(hào)被占用(不知道為什么GooglePlay的內(nèi)部測(cè)試和正式發(fā)布的版本號(hào)竟然不能重復(fù))。

      image
    • 填寫(xiě)剩下內(nèi)容并發(fā)廓脆。筛谚,回到內(nèi)部測(cè)試管理界面,選擇管理測(cè)試者停忿,將需要測(cè)試的Google賬號(hào)提交上去驾讲,并將“Opt-in URL”的地址復(fù)制下來(lái)。

    • 在測(cè)試機(jī)上登錄測(cè)試賬號(hào)瞎嬉,在瀏覽器里打開(kāi)剛剛的“Opt-in URL”地址蝎毡,即可加入內(nèi)測(cè)厚柳,并可以通過(guò)Google Play App下載測(cè)試版本的App氧枣。

    • 下載完成后,可以在/Android/obb/App包名/下看到一份嶄新的obb文件别垮。

解壓和下載

  • 解壓

    第一次安裝完app后便监,需要將obb文件進(jìn)行解壓并將解壓后的文件存儲(chǔ)到我們定義的文件夾里(可以是data/data/包名/files/也可以是內(nèi)置存儲(chǔ)下自定義的項(xiàng)目文件夾)。要想解壓obb文件碳想,第一步是獲取obb文件的本地路徑烧董,具體代碼如下:

    public static String getObbFilePath(Context context) {
        try {
            return Environment.getExternalStorageDirectory().getAbsolutePath()
                    + "/Android/obb/"
                    + context.getPackageName()
                    + File.separator
                    + "main."
                    + context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode
                    + "."
                    + context.getPackageName()
                    + ".obb";
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
    

    拿到obb文件路徑后,可以開(kāi)始進(jìn)行解壓了:

    public static void unZipObb(Context context) {
       String obbFilePath = getObbFilePath(context);
       if (obbFilePath == null) {
           return;
       } else {
           File obbFile = new File(obbFilePath);
           if (!obbFile.exists()) {
               //下載obb文件
           } else {
               File outputFolder = new File("yourOutputFilePath");
               if (!outputFolder.exists()) {
                   //目錄未創(chuàng)建 沒(méi)有解壓過(guò)
                   outputFolder.mkdirs();
                   unZip(obbFile, outputFolder.getAbsolutePath());
               } else {
                   //目錄已創(chuàng)建 判斷是否解壓過(guò)
                   if (outputFolder.listFiles() == null) {
                       //解壓過(guò)的文件被刪除
                       unZip(obbFile, outputFolder.getAbsolutePath());
                   }else {
                       //此處可添加文件對(duì)比邏輯
                   }
               }
           }
       }
    }
    

    谷歌官方有提供解壓obb文件的庫(kù)供開(kāi)發(fā)者使用胧奔,叫做APK Expansion Zip Library逊移,感興趣的小伙伴可以在一下路徑下查看。

    <sdk>/extras/google/google_market_apk_expansion/zip_file/
    

    筆者不推薦使用該庫(kù)龙填,原因是這個(gè)庫(kù)已經(jīng)編寫(xiě)了有一些年頭了胳泉,當(dāng)時(shí)編譯的sdk版本比較低,有一些兼容性的bug需要開(kāi)發(fā)者修改代碼后才能使用岩遗。所以這里使用的upzip方法是用最普通的ZipInputStream和FileOutputStream解壓zip包的方式來(lái)實(shí)現(xiàn)的:

    //這里沒(méi)有添加解壓密碼邏輯扇商,小伙伴們可以自己修改添加以下
    public static void unzip(File zipFile, String outPathString) throws IOException {
        FileUtils.createDirectoryIfNeeded(outPathString);
        ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFile));
        ZipEntry zipEntry;
        String szName;
        while ((zipEntry = inZip.getNextEntry()) != null) {
            szName = zipEntry.getName();
            if (zipEntry.isDirectory()) {
                szName = szName.substring(0, szName.length() - 1);
                File folder = new File(outPathString + File.separator + szName);
                folder.mkdirs();
            } else {
                File file = new File(outPathString + File.separator + szName);
                FileUtils.createDirectoryIfNeeded(file.getParent());
                file.createNewFile();
                FileOutputStream out = new FileOutputStream(file);
                int len;
                byte[] buffer = new byte[1024];
                while ((len = inZip.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                    out.flush();
                }
                out.close();
            }
        }
        inZip.close();
    }
    
    public static String createDirectoryIfNeeded(String folderPath) {
        File folder = new File(folderPath);
        if (!folder.exists() || !folder.isDirectory()) {
            folder.mkdirs();
        }
        return folderPath;
    }
    

    解壓完成后,就可以通過(guò)輸出文件的路徑來(lái)訪問(wèn)到我們需要訪問(wèn)的大容量資源了宿礁,文件的讀取在這里就不展開(kāi)了案铺。

  • 下載obb

    從Google Play下載和安裝App有一定概率會(huì)下載到不包含obb文件的apk,或者obb文件被人為刪除了梆靖。這種情況下控汉,需要開(kāi)發(fā)者到谷歌提供的下載地址處下載相應(yīng)的obb文件》滴牵可是要怎么獲取到下載地址呢姑子,這里使用了官方的Downloader Library

    這個(gè)庫(kù)可以通過(guò)Android Sdk Manager下載到思喊,打開(kāi)manager后勾上Google Play Licensing Library packageGoogle Play APK Expansion Library package點(diǎn)下載即可壁酬。可是在我興高采烈準(zhǔn)備大干一場(chǎng)的時(shí)候,發(fā)現(xiàn)它竟然編譯不過(guò)[捂臉]舆乔。這個(gè)庫(kù)和上面說(shuō)的APK Expansion Zip Library一樣岳服,由于年代久遠(yuǎn)又年久失修,基本不能使用了希俩。折騰了一些時(shí)間后吊宋,魔改了一個(gè)版本,才終于可以使用颜武。 這里提供一個(gè)編譯好的jar包google_apk_expand_helper璃搜。具體代碼如下:

    //隨機(jī)byte數(shù)組,隨便填就好
    private static final byte[] salt = new byte[]{18, 22, -31, -11, -54, 18, -101, -32, 43, 2, -8, -4, 9, 5, -106, -17, 33, 44, 3, 1};
    
    private static final String TAG = "Obb";
    
    public static void getObbUrl(Context context, String publicKey) {
        final APKExpansionPolicy aep = new APKExpansionPolicy(
                context,
                new AESObfuscator(salt, 
                                  context.getPackageName(),
                                  Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID)
                ));
        aep.resetPolicy();
    
        final LicenseChecker checker = new LicenseChecker(context, aep, publicKey);
    
        checker.checkAccess(new LicenseCheckerCallback() {
            @Override
            public void allow(int reason) {
                Log.i(TAG, "allow:" + reason);
                if (aep.getExpansionURLCount() > 0) {
                    //這里就是獲取到的地址
                    String url = aep.getExpansionURL(0);
                }
            }
    
            @Override
            public void dontAllow(int reason) {
                Log.i(TAG, "dontAllow:" + reason);
            }
    
            @Override
            public void applicationError(int errorCode) {
                Log.i(TAG, "applicationError:" + errorCode);
            }
        });
    }
    

    上述方法中需要提供參數(shù)publicKey鳞上,這個(gè)publicKey可以在GooglePlayConsole中找到这吻。

  • 小結(jié)

    掌握了上述的方法我們就已經(jīng)完成了Apk分包的主要流程了,以下內(nèi)容將舉例說(shuō)明如果通過(guò)配置gradle文件進(jìn)行多渠道打包篙议,如何在每次打包的時(shí)候自動(dòng)將大容量資源文件壓縮成obb等唾糯。

多渠道與自動(dòng)化

  • 例子

    假設(shè)我們現(xiàn)在需要發(fā)布一個(gè)超過(guò)100M的安裝包到GooglePlay以及應(yīng)用寶,對(duì)于GooglePlay來(lái)說(shuō)鬼贱,我們需要生成小于100M的apk文件和obb文件移怯,而對(duì)于應(yīng)用寶來(lái)說(shuō),只需要生成一個(gè)完整的apk即可这难。

    那么問(wèn)題來(lái)了舟误,我們不可能說(shuō)在打包GooglePlay的時(shí)候?qū)①Y源文件手動(dòng)移除并修改資源引用的相關(guān)邏輯,然后再在打包應(yīng)用寶的時(shí)候?qū)⑺麄兎呕貋?lái)姻乓,這樣做會(huì)大大增加開(kāi)發(fā)者的工作量并且增大出錯(cuò)的可能性嵌溢。那有沒(méi)有辦法在單個(gè)工程項(xiàng)目下既能打包GooglePlay的包又可以打包應(yīng)用寶的包呢?答案是有的糖权,build.gradle中的sourceSets就可以解決這樣的問(wèn)題堵腹。

  • 利用sourceSets隔離渠道資源和資源引用代碼

    假設(shè)我們有一個(gè)splash.mp4文件,在應(yīng)用寶中渠道包中星澳,它被放在了res/raw/目錄下疚顷。而在googlePlay渠道包中,它被放置在obb文件里禁偎,我們可以這么處理腿堤。

    首先,在src目錄下創(chuàng)建兩個(gè)新的目錄googlePlay和tencent如暖,并在他們的目錄下新建java字柠,res和assest文件夾浩村。

    image

    在app級(jí)別的build.gradle文件中添加GooglePlay和應(yīng)用寶的渠道信息:

    android {
        flavorDimensions "default"
        productFlavors {
        
            GooglePlay { dimension "default" }
            Tencent { dimension "default" }
        
            /** 在AndroidManifest.xml中加入 
                <meta-data android:name="Channel"
                           android:value="${CHANNEL_NAME}" />
            **/
        
            productFlavors.all { flavor ->
                flavor.manifestPlaceholders = [CHANNEL_NAME: name]
            }
    
        }
    }
    

    緊接其后添加sourceSets配置颂暇,指定不同渠道的資源和代碼地址,其中main為共有資源和代碼士修,其余的為對(duì)應(yīng)渠道包的資源和代碼:

    sourceSets {
        main {
            java.srcDirs = ['src/main/java']
            assets.srcDirs = ['src/main/assets']
            res.srcDirs = ['src/main/res']
        }
        GooglePlay {
            java.srcDirs = ['src/googlePlay/java']
            res.srcDirs = ['src/googlePlay/res']
            assets.srcDirs = ['src/googlePlay/assets']
        }
        Tencent {
            java.srcDirs = ['src/tencent/java']
            res.srcDirs = ['src/tencent/res']
            assets.srcDirs = ['src/tencent/assets']
        }
    }
    

    將splash.mp4放到tencent/res/raw/文件夾下,并為不同渠道的java文件夾新建包名文件夾以及ResourcesHelper.java樱衷,完成后的目錄結(jié)構(gòu)如下:

    image

    有兩點(diǎn)需要注意的地方:

    一是java包下必須創(chuàng)建包名文件夾棋嘲,否則會(huì)無(wú)法引用到項(xiàng)目下的類(lèi)。該例子中就是com.example.obbtest包矩桂。

    二是AndroidStudio中可以通過(guò)左下角的Build Variants窗口選擇當(dāng)前需要編譯的渠道包類(lèi)型沸移,當(dāng)選擇GooglePlay時(shí)會(huì)發(fā)現(xiàn)tencent下的java文件失效了。所以侄榴,如果需要修改某渠道下的java文件雹锣,請(qǐng)先通過(guò)Build Variants切換到指定渠道。

    最后癞蚕,針對(duì)不同渠道的ResourcesHelper.java采用不同的資源獲取方式:

    GooglePlay版本:

    public class ResourcesHelper {
       public static void playSplashVideoResource(VideoView videoView){
           String filePath = ObbHelper.getCurrentObbFileFolder()+"raw/"+"splash.mp4";
           videoView.setVideoPath(filePath);
       }
    }
    

    tencent版本:

    public class ResourcesHelper {
        public static void playSplashVideoResource(VideoView videoView) {
            int resource = R.raw.splash;
            String uri = "android.resource://" + videoView.getContext().getApplicationContext().getPackageName() + "/" + resource;
            videoView.setVideoURI(Uri.parse(uri));
        }
    }
    

    通過(guò)sourceSets隔離渠道資源和資源引用代碼在這里就完成了蕊爵,針對(duì)更加復(fù)雜的場(chǎng)景,就需要小伙伴根據(jù)實(shí)際情況進(jìn)行擴(kuò)展和修改了涣达。下面我們來(lái)看一下如何在構(gòu)建時(shí)自動(dòng)將資源打包成obb文件在辆。

  • 構(gòu)建時(shí)生成obb文件

    要在構(gòu)建時(shí)生成obb文件就必須通過(guò)添加gradle腳本來(lái)實(shí)現(xiàn)。我們先在項(xiàng)目目錄下新建一個(gè)腳本文件flavour.gradle度苔。

    然后,要想打包obb文件浑度,就必須知道現(xiàn)在構(gòu)建的是哪個(gè)渠道的包寇窑,那要怎么拿到現(xiàn)在的渠道呢,請(qǐng)看代碼:

    def String getCurrentFlavor() {
        Gradle gradle = getGradle()
        String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
    
        Pattern pattern;
    
        if (tskReqStr.contains("assemble"))
            pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
        else
            pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
    
        Matcher matcher = pattern.matcher(tskReqStr)
    
        if (matcher.find())
          return matcher.group(1).toLowerCase()
        else {
            println "NO MATCH FOUND"
            return ""
        }
    }
    

    我們知道obb的本質(zhì)就是zip文件箩张,所以只要在flavour.gradle中添加壓縮文件的方法甩骏,就可以達(dá)到生成obb的效果了。由于筆者的Groovy語(yǔ)言不精通先慷,所以這里使用java代碼來(lái)解決饮笛,在flavour.gradle中添加:

    import java.util.regex.Matcher
    import java.util.regex.Pattern
    import java.util.zip.ZipEntry
    import java.util.zip.ZipOutputStream
    
    ext {
        zipObb = this.&zipObb
        getCurrentFlavor = this.&getCurrentFlavor
    }   
    
    //外部壓縮方法入口,參數(shù)是所有需要壓縮文件的目錄以及輸出路徑论熙,同樣沒(méi)有添加壓縮密碼邏輯福青,小伙伴們需要的自己添加吧
    def static zipObb(File[] fs, String zipFilePath) {
        if (fs == null) {
            throw new NullPointerException("fs == null");
        }
        ZipOutputStream zos = null;
        try {
            zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFilePath)));
            for (File file : fs) {
                if (file == null || !file.exists()) {
                   continue;
                }
                compress(file, zos, file.getName());
            }
            zos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(zos != null){
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    //內(nèi)部遞歸壓縮方法
    def static compress(File sourceFile, ZipOutputStream zos, String name) throws Exception {
        byte[] buf = new byte[2048];
        if (sourceFile.isFile()) {
            // 向zip輸出流中添加一個(gè)zip實(shí)體,構(gòu)造器中name為zip實(shí)體的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip輸出流中
                int len;
            FileInputStream inputStream = new FileInputStream(sourceFile);
            while ((len = inputStream.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            inputStream.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原來(lái)的文件結(jié)構(gòu)時(shí),需要對(duì)空文件夾進(jìn)行處理
                zos.putNextEntry(new ZipEntry(name + "/"));
                // 沒(méi)有文件脓诡,不需要文件的copy
                zos.closeEntry();
            } else {
                for (File file : listFiles) {
                    compress(file, zos, name + "/" + file.getName());
                }
            }
        }
    }
    def String getCurrentFlavor() {
        ........
    }
    

    我們已經(jīng)在flavour.gradle中添加了獲取當(dāng)前渠道和壓縮文件的方法了无午,現(xiàn)在回到app下的build.gradle文件中,通過(guò)判斷當(dāng)前渠道是否GooglePaly祝谚,對(duì)需要壓縮的所有文件進(jìn)行壓縮宪迟,并輸出到googlePlay渠道包apk的同級(jí)目錄下:

    apply from: "../flavour.gradle"
    
    //添加到文件最后 
    //自動(dòng)打包擴(kuò)展文件obb
    task zipObb(type: JavaExec) {
        //判斷是否GooglePlay渠道包,獲取渠道包的時(shí)候做了小寫(xiě)處理
        if (getCurrentFlavor().equals("googleplay")) {
            //獲取debug還是release模式輸出到不同地址
            String outputFilePath
            if(gradle.startParameter.taskNames.toString().contains("Debug")){
                outputFilePath = "app/build/outputs/apk/GooglePlay/debug/main." + android.defaultConfig.versionCode + ".com.example.testobb.obb"
            }else{
                outputFilePath = "app/GooglePlay/release/main." + android.defaultConfig.versionCode + ".com.example.testobb.obb"
            }
            File file = new File('app/src/tencent/res/raw/splash.mp4')
            //此處添加更多文件 也可以通過(guò)配置文件的方式輸入需要打包obb的所有資源文件
            File[] files = new File[]{file}
            zipObb(files, outputFilePath)
        }
    }
    

    至此交惯,我們的多渠道打包和自動(dòng)化生成obb就實(shí)現(xiàn)了次泽。

    如發(fā)現(xiàn)任何錯(cuò)誤或有不明白的地方可以留言穿仪。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市意荤,隨后出現(xiàn)的幾起案子牡借,更是在濱河造成了極大的恐慌,老刑警劉巖袭异,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钠龙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡御铃,警方通過(guò)查閱死者的電腦和手機(jī)碴里,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)上真,“玉大人咬腋,你說(shuō)我怎么就攤上這事∷ィ” “怎么了根竿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)就珠。 經(jīng)常有香客問(wèn)我寇壳,道長(zhǎng),這世上最難降的妖魔是什么妻怎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任壳炎,我火速辦了婚禮,結(jié)果婚禮上逼侦,老公的妹妹穿的比我還像新娘匿辩。我一直安慰自己,他們只是感情好榛丢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布铲球。 她就那樣靜靜地躺著,像睡著了一般晰赞。 火紅的嫁衣襯著肌膚如雪稼病。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天宾肺,我揣著相機(jī)與錄音溯饵,去河邊找鬼。 笑死锨用,一個(gè)胖子當(dāng)著我的面吹牛丰刊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播增拥,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼啄巧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寻歧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起秩仆,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤码泛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后澄耍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體噪珊,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年齐莲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痢站。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡选酗,死狀恐怖阵难,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芒填,我是刑警寧澤呜叫,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站殿衰,受9級(jí)特大地震影響朱庆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜播玖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一椎工、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜀踏,春花似錦、人聲如沸掰吕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)殖熟。三九已至局待,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間菱属,已是汗流浹背钳榨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纽门,地道東北人薛耻。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赏陵,于是被迫代替她去往敵國(guó)和親饼齿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饲漾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • swift中考传,網(wǎng)絡(luò)圖片庫(kù)比較常用的是kingfisher和alamofireimage,個(gè)人感覺(jué)alamofire...
    revon閱讀 5,030評(píng)論 3 2
  • 你相信命運(yùn)嗎证鸥?人生有所謂的定數(shù)嗎僚楞?答案?jìng)€(gè)人各異,但你對(duì)這兩者的定論將決定你今后的生活
    一天一點(diǎn)進(jìn)步閱讀 96評(píng)論 0 0
  • 秋葵枉层,我對(duì)它并不是很熟悉泉褐,第一次吃秋葵,覺(jué)得它長(zhǎng)得像黃瓜返干,但又棱角分明兴枯,味道卻不是像黃瓜那樣爽口。我畫(huà)的這枝秋葵矩欠,...
    林下生風(fēng)閱讀 642評(píng)論 5 23
  • IP地址的組成和分級(jí) IP 的表示式:00000000.00000000.00000000.00000000 ==...
    whillysnie閱讀 287評(píng)論 0 0