preface
The company needs to split the APP into two versions: cloud deployment and enterprise. A. The cloud deployment version is the original APP, which remains unchanged. B. The enterprise version is a new app, which has different interface and functions from the cloud deployment. Users can install both apps on their phones at the same time.
A break-up
According to the requirements, first of all, the two apps must be one project, and it is impossible to copy a copy of the code for separate maintenance. At least deal with these things:
-
Gradle needs to support differentiated packaging. It needs to be able to package two APKs through AndroidStudio, and the registration of these two apps cannot be the same, so that they can be installed on the same phone at the same time.
-
There is a global field in the code to distinguish between the two versions of the interface differentiation (APP name, icon), some functions
-
Since our app has push service, it is necessary to ensure that the push of two apps do not interfere with each other. Click the notification bar of push message to jump to the specified APP
-
Our APP has the function of QQ/ wechat sharing. If you want to share a web page to QQ, click the message in QQ to correctly start and jump to the current sharing app.
-
If you use TeamCity, differentiate your scripts. (Note: The current two projects are the same SVN branch)
The solution
- Gradle needs to support differentiated packaging. First, what two apps can be installed on the same phone? A lot of people say the name of the bag is different. In AndroidStudio, different apps can be installed on the same phone. Androidmanifest.xml is a different moduler, and the package in each androidmanifest.xml file is different. This package affects the package names of r.java.xxx within each Moduler, as well as the package names of all Java files within this Moduler. The package must be different for different Modulers so we can use the same resource file name and Java file name for different modulers.
The applicationId defined in build.gradle in the app directory:
Gradle builds two apps using packageName and applicationId. Is simple:
productFlavors {
cloud {
// Cloud deployment version
resValue "string"."app_name"."MyLuban"
resValue "string"."app_scheme"."bv4phone"
resValue "string"."app_link_scheme"."cloud"
manifestPlaceholders = [app_icon:"@drawable/ic_launcher"]
}
entp {
// Enterprise version
applicationIdSuffix ".entp"
resValue "string"."app_name".MyLuban Enterprise Edition
resValue "string"."app_scheme"."bv4phoneentp"
resValue "string"."app_link_scheme"."entp"
manifestPlaceholders = [app_icon:"@drawable/ic_launcher_entp"]}}Copy the code
The key code is :(ignore other code for now)
// Enterprise version
applicationIdSuffix ".entp"
Copy the code
Append the applicationId of the enterprise version of the app to distinguish it from cloud deployment. Be careful not to change the applicationId for cloud deployment, because your app is the same applicationId in the app marketplace and will no longer be available.
- Interface and functional differentiation
How to customize different app names:
resValue "string"."app_name"."MyLuban"
Copy the code
This statement can define any different String, such as app_name and MyLuban. Then use it in manifest.xml:
android:label="@string/app_name"
Copy the code
Customize different app ICONS:
manifestPlaceholders = [app_icon:"@drawable/ic_launcher"]
Copy the code
In manifest.xml:
android:icon="${app_icon}"
Copy the code
The BuildConfig file in the build folder will show the build information for this app once we add product-differentiated build:
//APP product type
switch (BuildConfig.FLAVOR){
case "cloud":
ProductUtil.setProductType(CLOUD);
break;
case "entp":
ProductUtil.setProductType(ENTERPRISE);
break;
}
Copy the code
ProductUtil is as simple as a set/get method, and then anyone else can get the product type of the current app and continue to differentiate the interface and functionality.
One more quick question, if I hit Run, which app will be compiled by AS? The default execution of run is productFlavors, which is sorted top to bottom on AS1.5, and debug, which is sorted alphabetically on AS2.1.
- Push differentiation The push service of our app is realized based on webSocket itself, and the service is run in the separate process to obtain push. Even with third-party push, the principle is similar. So, after running two apps on the phone, will push services interfere with each other?
But when you click the Notification jump app, it’s time to tell the difference. IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: 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>
Copy the code
Data is distinguished by two different fields. The fields are generated in Gradle (see gradle configuration above) and then distinguished in the Intent location:
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"));
/ /...
Copy the code
-
Sharing differentiation If your sharing also opens a web page, click the button on the web page to launch your app. IntentFilter = IntentFilter = IntentFilter = IntentFilter Just want to cooperate with the front end, according to the sharing of different products, set up different schemes.
-
Teamcity is a tool for continuous integration, mainly for the convenience of testing can compile the latest code at any time with one click, package APK. Teamcity typically sets up different build options for different projects. In this case, our two apps are actually the same SVN branch. How can we distinguish them? The answer is to create two sets of build scripts, which Gradle supports: (since every company teamCity is different, post the key code) :
set build_cmd=assembleCloudRelease
if "% 2%"= ="myluban_enterprise" (
set apk_prefix=myluban_entp
set build_cmd=assembleEntpRelease
)
echo //////// compile 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
Copy the code
This is essentially executing two different gradle commands.
other
This article summarizes the strategy of app splitting, and some of the problems to be solved. If you have any questions, please leave a comment.