My blog
The original address

As we all know, channel package is a common distribution method in the Domestic Android application market. The channel package will contain different channel information, so that we can make follow-up statistics on the downloads, users and retention rate of the App in various distribution channels, and adjust the application content or promotion plan accordingly. As it is more and more difficult for iOS apps to be launched in China, many enterprise packages have been derived. In order to facilitate data collection, multi-channel schemes are also used.

In addition, during the progress of the project, there may be some demands for temporary new channels, and it will be time-consuming to go back to the project to repackage. Is there any way to speed up the packaging? Some of the options are shared below.

IOS multi-channel packaging solution

At present, there are only two ways of iOS channel package, one is through multiple targets, the other is to modify the plist file.

Multiple target way

Click Target in the project and right-click Duplicate. You can modify the target name, PList name, and Scheme name in the red box.

You can determine the current target by adding a macro definition by going to the Preprocessor Macros in Build Settings and filling in the macro definition name.

The code looks like this:

#ifdef  TARGET1MACROS
    // target1
#elif defined TARGET2MACROS
    // target2
#endifCopy the code

Specific package script is not introduced, readers can search online, the disadvantage of this way is a channel to play once, low efficiency. The following focuses on changing the batch packaging mode of PList.

Change the PLIST mode

Here’s a simple Demo:

Step 1: Create a project named MultiChannelDemo and create a channel. plist file in the project. Set the Channel field to channel01. Then set a label label on the page to display the current channel name, which can be obtained using the following code:

NSDictionary *channelDic = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Channel" ofType:@"plist"]];
NSString *channel = channelDic[@"Channel"];Copy the code

Step 2: Create a parent package for this project with the available certificate. Unzip the ipA package and you can get a folder named Payload.

├ ─ ─ Base. Lproj ├ ─ ─ Channel. The plist ├ ─ ─ the Info. The plist ├ ─ ─ MultiChannelDemo ├ ─ ─ PkgInfo ├ ─ ─ _CodeSignature └ ─ ─ embedded.mobileprovisionCopy the code

As you can see, channel. plist is the plist that stores the Channel information created in the previous project. We will modify the Channel to generate a new Channel package.

Step 3: Extract the description file for re-signing. The folder Payload in the previous step contains the Embedded. Mobileprovision file.

Step 4: Create a new plain text and enter the channel number you want to add, such as:

Step 5: Create a script file, channelpackage. sh, that reads as follows:

#! / bin/bash # enter the package name name = "MultiChannelDemo" echo "-- -- -- -- -- - the SDK channel package -- -- -- -- -- -- -- -- -- --" appName = "${name}. The app" PlistBuddy =" /usr/libexec/plistbuddy "configName="Payload/${appName}/ channel. plist" ipa="${name} OutUpdateAppDir ="ChannelPackages" # entitlements. Plist path entitlementsDir="entitlements. Plist "# Switch to current directory currDir=${PWD} CD ${currDir} echo "-----${currDir}" rm -rf Payload Unzip -o -q ${ipa} # delete old folder, re generated rm -rf ${outUpdateAppDir} mkdir ${outUpdateAppDir} # delete old entitlements. Plist, / Re-generated RM -rf ${entitlementsDir} /usr/libexec/PlistBuddy -x -c "print :Entitlements "/dev/stdin <<< $(security CMS -d -i Payload/${appName}/embedded.mobileprovision) > entitlements.plist echo "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- start packing process -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" # channel list file start packing for the line in $(cat ChannelList. TXT) # circular array, $plistBuddy -c "Set :Channel $line" ${configName} # app re-sign rm -rf Content / ${appName} / _CodeSignature cp embedded mobileprovision "Payload / ${appName} / embedded mobileprovision" # fill in the ID certificate is available  codesign -f -s "iPhone Distribution: XXXXXX. "Payload / ${appName} - entitlements ${entitlementsDir} # if output content/MultiChannelDemo app: Replacing existing Signatures is a step in replacing existing signatures. Replacing existing Signatures is a step in replacing existing signatures. Zip -rq "${outUpdateAppDir}/$line.ipa" Payload echo "........ Channel ${line} packing is done "doneCopy the code

Please modify the information in the script according to your actual situation. All the preparations have been completed and the required documents are as follows:

├── Bass Exercises ── Bass Exercises ── bass Exercises ── bass Exercises ── Bass ExercisesCopy the code

Step 6: Execute the script file in the current directory:

sh ChannelPackage.shCopy the code

The generated ChannelPackages folder after the package is completed is the channel package we need:

├ ─ ─ ChannelList. TXT ├ ─ ─ ChannelPackage. Sh ├ ─ ─ ChannelPackages │ ├ ─ ─ channel02. Ipa │ ├ ─ ─ channel03. Ipa │ └ ─ ─ ├── Heavy Bass Exercises ── Heavy Bass Exercises ── Heavy Bass Exercises ── entitlements.plistCopy the code

This way of automatic packaging can avoid part of Xcode packaging compilation time, fast package out.

Android multi-channel packaging solution

The following is an open source Walle from Meituan Technology team. It has Gradle plug-in and command line. The former can be integrated quickly, and the latter can meet the needs of customization.

Gladle plug-in mode

To configure the build. Gradle

Add the Walle plugin dependency to the build.gradle file in the project root directory:

Buildscript {dependencies {classpath 'com. At meituan. Android. Walle: plugin: 1.1.6'}}Copy the code

Build. Gradle file in app directory:

Apply the plugin: 'walle' dependencies {the compile 'com. At meituan. Android. Walle: library: 1.1.6'}Copy the code

Configure the plug-in

Configure channels in build.gradle file in app directory:

Outputs /channels walle {// apkOutputFolder = new File("${project.builddir}/outputs/channels"); ApkFileNameFormat = '${appName}_v${versionName}_${channel}. ChannelFile = new File("${project.getprojectdir ()}/channel")}Copy the code

For details about the format of a channel profile, see Channel Profile Example.

How to obtain channel information

Quote this code where you need to fill in channel information:

String channel = WalleChannelReader.getChannel(this.getApplicationContext());Copy the code

How to generate channel packages

Export the APK package with the Assemble ${variantName}Channels directive.

Command-line mode

From the command line, you can export the APK of the new channel without opening the IDE. The steps are as follows:

First, create a folder, grab one of the APK packages exported in the previous steps, and then download Walle-cli-all.jar, both placed in this folder directory.

Then, execute the command under the folder directory:

java -jar walle-cli-all.jar put -c ${channelName} ${apkName}.apkCopy the code

If the preceding command is executed successfully, a new channel package named ${apkName}_${channelName}.apk is generated in the current directory

If you want to write channels in batches, separate them with commas:

java -jar walle-cli-all.jar batch -c ${channelName0},${channelName1},${channelName2} ${apkName}.apkCopy the code

Or specify a channel profile:

java -jar walle-cli-all.jar batch -c ${channelFile} ${apkName}.apkCopy the code

If you want to write additional information, see
The official documentation.

To check/display channels, the command is:

java -jar walle-cli-all.jar show ${apkName}.apkCopy the code

Walle can now meet the security requirements of the new application signature scheme, and also meet the requirements of channel package packaging time. If you need it, you can try it.