app拆分,多產(chǎn)品打包實(shí)錄.md

本篇文章已授權(quán)微信公眾號 hongyangAndroid (鴻洋)獨(dú)家發(fā)布

前言

公司有需求app需要拆分為兩個:云部署版和企業(yè)版。
a.云部署版就是原app ,保持不變
b.企業(yè)版是新app,與云部署的界面,功能有差異,并且不上架應(yīng)用市場,只在企業(yè)內(nèi)網(wǎng)使用。用戶手機(jī)上可以同時安裝這兩個app。

拆分策略

根據(jù)需求,首先兩個app肯定是一個項(xiàng)目,不可能再copy一份代碼分開維護(hù)。那么至少要處理這些事務(wù):

  1. gradle要支持差異化打包,通過AndroidStudio要能夠打包出兩個apk,并且這兩個app的報名不能一樣,才能同時安裝在同一部手機(jī)上。

  2. 代碼中有一個全局字段,區(qū)分兩個版本做界面的差異化(app名稱,圖標(biāo)),一些功能

  3. 由于我們app有推送服務(wù) ,要保證兩個app的推送互不干擾,點(diǎn)擊推送消息的通知欄能夠跳到指定app

  4. 我們app有QQ/微信分享功能,假設(shè)分享一個網(wǎng)頁到QQ,那么點(diǎn)擊qq里面的消息要能正確啟動并跳轉(zhuǎn)到當(dāng)前分享的app。

  5. 如果你們使用了teamcity,還要差異化編譯腳本。(注意:當(dāng)前兩個項(xiàng)目是同一個svn分支)

解決方案

  • gradle要支持差異化打包
    先思考下什么樣的兩個app能夠安裝在同一部手機(jī)上?很多人說包名不同。
    其實(shí)這個是eclipse時代的說法,到了AndroidStudio上準(zhǔn)確來講,是ApplicationId不同的app可以安裝在同一部手機(jī)上??梢钥聪翧ndroidStudio下構(gòu)建的項(xiàng)目,不同的moduler里面都有一個AndroidManifest.xml文件,并且每個AndroidManifest.xml里面package都不同,這個package影響的是每個moduler里面R.java.xxx的包名,以及這個moduler內(nèi)所有java文件的包名。不同的moduler這個package肯定不同所以我們在不同的moduler可以使用相同的資源文件名,和java文件名。

再說app目錄下build.gradle里面定義的applicationId:


image.png

這個值默認(rèn)跟app目錄下manifest.xml里面package一樣,如果你不寫的話。這個才是決定app唯一性的字段(不僅是本地安裝,也包括應(yīng)用市場判斷的依據(jù))。

OK,明白了packageName和applicationId的區(qū)別,如何用gradle構(gòu)建兩個app呢?很簡單:

productFlavors {
    cloud {
        //云部署版本
        resValue "string","app_name", "MyLuban"
        resValue "string","app_scheme", "bv4phone"
        resValue "string","app_link_scheme", "cloud"
        manifestPlaceholders = [app_icon:"@drawable/ic_launcher"]
    }
    entp {
        //企業(yè)版本
        applicationIdSuffix ".entp"
        resValue "string","app_name", "MyLuban企業(yè)版"
        resValue "string","app_scheme", "bv4phoneentp"
        resValue "string","app_link_scheme", "entp"
        manifestPlaceholders = [app_icon:"@drawable/ic_launcher_entp"]
    }
}

關(guān)鍵代碼是:(其他代碼先忽略)

        //企業(yè)版本
        applicationIdSuffix ".entp"

給企業(yè)版的app的applicationId加后綴,就可以和云部署區(qū)分開了。注意千萬不要改變云部署的applicationId,因?yàn)槟愕腶pp在應(yīng)用市場就是原來的applicationId,一旦改了就無法再覆蓋上架了。


image.png
  • 界面和功能差異化

如何定制不同的app名稱:

resValue "string","app_name", "MyLuban"

這個語句可以定義任何不同的String,比如這里名字為app_name,取值MyLuban。然后在manifest.xml中使用:

android:label="@string/app_name"

定制不同的app圖標(biāo):

manifestPlaceholders = [app_icon:"@drawable/ic_launcher"]

在manifest.xml中使用:

android:icon="${app_icon}"

當(dāng)我們加入產(chǎn)品差異化編譯一次后,在build文件夾的BuildConfig文件可以看到這個app的編譯信息:


image.png

因此我們可以寫一個工具類,來保存當(dāng)前的產(chǎn)品類型,在Application的onCreate里面初始化:

//APP產(chǎn)品類型
switch (BuildConfig.FLAVOR){
    case "cloud":
        ProductUtil.setProductType(CLOUD);
        break;
    case "entp":
        ProductUtil.setProductType(ENTERPRISE);
        break;
}

ProductUtil里面很簡單就是set/get方法,然后其他任何就可以獲取當(dāng)前app的產(chǎn)品類型,繼續(xù)做界面和功能的差異化。

還有個小問題,此時點(diǎn)擊run,AS會編譯哪個app呢?
點(diǎn)擊run的默認(rèn)執(zhí)行:在AS1.5是按照productFlavors 排序從上到下的,執(zhí)行debug編譯
在AS2.1之后是按照首字母排序,比如這里就是執(zhí)行 cloud-debug版本
更改方式:


image.png
  • 推送差異化
    我們app的推送服務(wù)是基于webSocket自己實(shí)現(xiàn)的,單獨(dú)開啟進(jìn)程里運(yùn)行service來實(shí)現(xiàn)獲取推送。即使使用第三方的推送,原理也差不多。
    那么,手機(jī)上運(yùn)行兩個app之后,推送服務(wù)會相互干擾嗎?
image.png

很簡單看下手機(jī)設(shè)置里面的應(yīng)用進(jìn)程就知道,兩個app進(jìn)程包括啟動的推送Servcie進(jìn)程,完全獨(dú)立,這樣就可以保證app的推送互不干擾而不需要特殊處理。

但是點(diǎn)擊推送消息通知欄跳轉(zhuǎn)app,就要區(qū)分開了。因?yàn)檫@里的跳轉(zhuǎn)一般是Intent隱式跳轉(zhuǎn),我們應(yīng)該為跳轉(zhuǎn)目標(biāo)Activity的IntentFilter做差異化:

<intent-filter>
    <action android:name="com.myluban.push" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="@string/app_link_scheme" />
</intent-filter>

用兩個不同的字段區(qū)分data,字段在gradle里面生成(看上文的gradle配置),然后在啟動Intent的位置作區(qū)分:

private String PUSH_SCHEME = "cloud";
f(ProductUtil.getProductType()==ProductType.ENTERPRISE){
    PUSH_SCHEME = "entp";
}
Intent jumpIntent = new Intent("com.myluban.push");
jumpIntent.setData(Uri.parse(PUSH_SCHEME + "://abc"));
//...
  • 分享差異化
    如果你的分享也是打開一個網(wǎng)頁,點(diǎn)擊網(wǎng)頁上的按鈕啟動自身app。那么,跟推送跳轉(zhuǎn)類似,也是在IntentFilter作區(qū)分。只不過要前端配合一下,根據(jù)不同產(chǎn)品的分享,設(shè)置不同的scheme。

  • teamcity編譯腳本差異化
    teamcity是用于持續(xù)集成的工具,主要是方便測試可以隨時一鍵編譯最新代碼,打包apk。teamcity一般是根據(jù)不同的項(xiàng)目,建立不同的編譯選項(xiàng)。那這里我們兩個app其實(shí)是同一個svn分支,怎么區(qū)分呢?答案就是建立兩套編譯腳本,gradle是支持的:(由于每個公司teamcity都不一樣,貼出關(guān)鍵代碼):

set build_cmd=assembleCloudRelease
if "%2%"=="myluban_enterprise" (
    set apk_prefix=myluban_entp
    set build_cmd=assembleEntpRelease
) 
echo //////// 編譯release apk ////////
set srcPack=%apk_prefix%-release.apk
call %workDir%/gradlew.bat -b %workDir%/%projectDir%/build.gradle %build_cmd% -Ptargetdir=%cd%\%workDir%\release -Papkname=%srcPack% -x lint

其實(shí)就是執(zhí)行2個不同gradle命令。

其他

本文總結(jié)了app拆分的策略,以及一些問題的解決,還有其他疑問歡迎留言。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,733評論 25 709
  • Gradle對于很多開發(fā)者來說有一種既熟悉又陌生的感覺,他是離我們那么近,以至于我每天做項(xiàng)目都需要他,但是他又是離...
    阿_希爸閱讀 9,686評論 10 199
  • 遇不到給你安全感的人不要緊,要學(xué)會自己給自己力量。 看書、聽歌、跑步,你喜歡的任何事都行。 認(rèn)真豐富自己,安頓正負(fù)...
    篤學(xué)青衿閱讀 216評論 0 0
  • 寫在前面 (這是一堆廢話,可以不看,往下拉?。?大二那年,思考人的一生應(yīng)該怎樣度過才有意義?保爾說,為人類的解放而...
    請叫我鄭老師閱讀 362評論 0 4
  • 突然一看日歷,哇,好快!端午都已經(jīng)過完了。此刻,我心里只有無限感慨。 26+27號,由于工作很忙,麻煩事較多,都沒...
    天晴落雨閱讀 250評論 0 0

友情鏈接更多精彩內(nèi)容