AndroidStudio设置Android开发经验谈Android开发

app拆分,多产品打包实录.md

2018-02-02  本文已影响616人  08_carmelo

本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布

前言

公司有需求app需要拆分为两个:云部署版和企业版。
a.云部署版就是原app ,保持不变
b.企业版是新app,与云部署的界面,功能有差异,并且不上架应用市场,只在企业内网使用。用户手机上可以同时安装这两个app。

拆分策略

根据需求,首先两个app肯定是一个项目,不可能再copy一份代码分开维护。那么至少要处理这些事务:

  1. gradle要支持差异化打包,通过AndroidStudio要能够打包出两个apk,并且这两个app的报名不能一样,才能同时安装在同一部手机上。

  2. 代码中有一个全局字段,区分两个版本做界面的差异化(app名称,图标),一些功能

  3. 由于我们app有推送服务 ,要保证两个app的推送互不干扰,点击推送消息的通知栏能够跳到指定app

  4. 我们app有QQ/微信分享功能,假设分享一个网页到QQ,那么点击qq里面的消息要能正确启动并跳转到当前分享的app。

  5. 如果你们使用了teamcity,还要差异化编译脚本。(注意:当前两个项目是同一个svn分支)

解决方案

再说app目录下build.gradle里面定义的applicationId:


image.png

这个值默认跟app目录下manifest.xml里面package一样,如果你不写的话。这个才是决定app唯一性的字段(不仅是本地安装,也包括应用市场判断的依据)。

OK,明白了packageName和applicationId的区别,如何用gradle构建两个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 {
        //企业版本
        applicationIdSuffix ".entp"
        resValue "string","app_name", "MyLuban企业版"
        resValue "string","app_scheme", "bv4phoneentp"
        resValue "string","app_link_scheme", "entp"
        manifestPlaceholders = [app_icon:"@drawable/ic_launcher_entp"]
    }
}

关键代码是:(其他代码先忽略)

        //企业版本
        applicationIdSuffix ".entp"

给企业版的app的applicationId加后缀,就可以和云部署区分开了。注意千万不要改变云部署的applicationId,因为你的app在应用市场就是原来的applicationId,一旦改了就无法再覆盖上架了。


image.png

如何定制不同的app名称:

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

这个语句可以定义任何不同的String,比如这里名字为app_name,取值MyLuban。然后在manifest.xml中使用:

android:label="@string/app_name"

定制不同的app图标:

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

在manifest.xml中使用:

android:icon="${app_icon}"

当我们加入产品差异化编译一次后,在build文件夹的BuildConfig文件可以看到这个app的编译信息:


image.png

因此我们可以写一个工具类,来保存当前的产品类型,在Application的onCreate里面初始化:

//APP产品类型
switch (BuildConfig.FLAVOR){
    case "cloud":
        ProductUtil.setProductType(CLOUD);
        break;
    case "entp":
        ProductUtil.setProductType(ENTERPRISE);
        break;
}

ProductUtil里面很简单就是set/get方法,然后其他任何就可以获取当前app的产品类型,继续做界面和功能的差异化。

还有个小问题,此时点击run,AS会编译哪个app呢?
点击run的默认执行:在AS1.5是按照productFlavors 排序从上到下的,执行debug编译
在AS2.1之后是按照首字母排序,比如这里就是执行 cloud-debug版本
更改方式:


image.png image.png

很简单看下手机设置里面的应用进程就知道,两个app进程包括启动的推送Servcie进程,完全独立,这样就可以保证app的推送互不干扰而不需要特殊处理。

但是点击推送消息通知栏跳转app,就要区分开了。因为这里的跳转一般是Intent隐式跳转,我们应该为跳转目标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>

用两个不同的字段区分data,字段在gradle里面生成(看上文的gradle配置),然后在启动Intent的位置作区分:

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"));
//...
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

其实就是执行2个不同gradle命令。

其他

本文总结了app拆分的策略,以及一些问题的解决,还有其他疑问欢迎留言。

上一篇下一篇

猜你喜欢

热点阅读