之前的文章 《创造 | 一个强大的 Android 自动化打包脚本》 介绍了 Android 自动打包脚本的装备。其实之前的脚本里还有些多途径打包的装备完成方法并不好,比方运用 32 位仍是 64 位 NDK 的问题。最近我对这个装备的打包做了更新。此外,由于 Google Play 检测出我在应用里边运用了友盟的 SDK,违反了谷歌的开发者方针,所以我决定将海外版别的应用的崩溃信息计算切换到谷歌的 Firebase,因此也需要做多途径的装备。

多渠道打包配置和打包脚本修改

1、针对不同 NDK 的区分

首要,针对运用不同 NDK 的装备,我将 Gradle 装备文件修正位经过外部传入参数的方法进行设置,具体的脚本如下,

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    defaultConfig {
        if (project.hasProperty("build_ndk_type") && build_ndk_type == "ndk_32") {
            println(">>>>>>>> NDK option: using 32 bit version")
            ndk {abiFilters 'armeabi-v7a', 'x86'}
        } else if (project.hasProperty("build_ndk_type") && build_ndk_type == "ndk_32_64") {
            println(">>>>>>>> NDK option: using 32 and 64 bit version")
            ndk {abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a', 'x86_64'}
        } else {
            // default is 64 bit version
            print(">>>>>>>> NDK option: using 64 bit version")
            ndk {abiFilters 'arm64-v8a', 'x86_64'}
        }
    }
}

这样,就能够经过打包指令的参数动态指定运用哪种方法的 NDK,

./gradlew resguardNationalDebug -Pbuild_ndk_type=ndk_32

2、针对海内和海外不同依靠的调整

这方面做了两个当地的调整。一个是由于对 Debug 和 Release 版别或许不同的 Flavor,Gradle 会生成不同的依靠指令,所以针对不同的途径能够运用如下的指令进行依靠,

// apm
nationalImplementation "com.umeng.umsdk:common:$umengCommonVersion"
nationalImplementation "com.umeng.umsdk:asms:$umengAsmsVersion"
nationalImplementation "com.umeng.umsdk:apm:$umengApmVersion"
internationalImplementation 'com.google.firebase:firebase-analytics'
internationalImplementation platform("com.google.firebase:firebase-bom:$firebaseBomVersion")
internationalImplementation 'com.google.firebase:firebase-crashlytics'
// debugtools
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
debugImplementation 'com.github.Shouheng88:uetool-core:1.0'
debugImplementation 'com.github.Shouheng88:uetool-base:1.0'
releaseImplementation 'com.github.Shouheng88:uetool-no-op:1.0'
debugImplementation "com.facebook.stetho:stetho:$stethoVersion"
debugImplementation "com.iqiyi.xcrash:xcrash-android-lib:$xCrashVersion"

这儿针对了 national 和 international 两个 flavor 分别运用了 nationalImplementation 和 internationalImplementation 两个依靠指令。此外,针对一些只在 Debug 环境中运用的依靠,这儿运用了 debugImplementation 声明为只在 Debug 包里运用。

另一个调整是,由于比方假如咱们只在 Debug 环境中或许个别途径中运用某些依靠的话,那么当打 Release 包或许其他途径的时分就可能呈现依靠找不到的状况。这种状况的一种处理措施是像 leakcanary 一样,声明一个 no-op 的依靠,只包含必要的类文件而不包含具体的完成。此外,也能够经过下面的方法处理。

首要在项目中添加一个 module 或许运用已有的 module,然后已 CompileOnly 的方法引证上述依靠,

// apm
compileOnly "com.umeng.umsdk:common:$umengCommonVersion"
compileOnly "com.umeng.umsdk:asms:$umengAsmsVersion"
compileOnly "com.umeng.umsdk:apm:$umengApmVersion"
compileOnly 'com.google.firebase:firebase-analytics'
compileOnly platform("com.google.firebase:firebase-bom:$firebaseBomVersion")
compileOnly 'com.google.firebase:firebase-crashlytics'
// debugtool
compileOnly "com.facebook.stetho:stetho:$stethoVersion"
compileOnly "com.iqiyi.xcrash:xcrash-android-lib:$xCrashVersion"

这样是否运用某个依靠就取决于主 module. 然后,对需要引证到的类做一层包装,主 module 不直接调用依靠中的类,而是调用咱们包装过的类。

object UmengConfig {
    /** Config umeng library. */
    fun config(application: Application, isDev: Boolean) {
        if (!AppEnvironment.DEPENDENCY_UMENG_ANALYTICS) {
            return
        }
        if (!isDev) {
            UMConfigure.setLogEnabled(isDev)
            UMConfigure.init(application, UMConfigure.DEVICE_TYPE_PHONE, "")
            MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO)
        }
    }
}

这样,主 module 只需要在 application 里边调用 UmengConfig 的 config 方法即可。这儿咱们能够经过是否为 Debug 包来决定是否调用 Umeng 的一些方法,所以,这种方法能够确保打包没问题,只要 Release 版别调用不到 Umeng SDK 的类也不会呈现类找不到的异常。此外,也能够经过如下方法

public class AppEnvironment {
    public static final boolean DEPENDENCY_UMENG_ANALYTICS;
    public static final boolean DEPENDENCY_STETHO;
    public static final boolean DEPENDENCY_X_CRASH;
    static {
        DEPENDENCY_UMENG_ANALYTICS  = findClassByClassName("com.umeng.analytics.MobclickAgent");
        DEPENDENCY_STETHO           = findClassByClassName("com.facebook.stetho.Stetho");
        DEPENDENCY_X_CRASH          = findClassByClassName("xcrash.XCrash");
    }
    private static boolean findClassByClassName(String className) {
        boolean hasDependency;
        try {
            Class.forName(className);
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }
        return hasDependency;
    }
}

即经过能否找到某个类来判别当时环境中是否引证了指定的依靠,假如没有指定的依靠,直接跳过某些类的调用即可。

用上面的方法即能够处理 Android 中的各种多途径打包问题。

3、经过外部参数指定打包版别

这个比较简略,和装备 NDK 的方法相似,只需要经过判别指定的特点是否存在即可,

if (project.hasProperty("version_code")) {
    println(">>>>>>>> Using version code: " + version_code)
    versionCode = version_code.toInteger()
} else {
    versionCode = rootProject.ext.versionCode
}
if (project.hasProperty("version_name")) {
    println(">>>>>>>> Using version name: " + version_name)
    versionName = version_name
} else {
    versionName = rootProject.ext.versionName
}

这样装备之后打包的传参指令为,

./gradlew assembleNationalDebug -Pbuild_ndk_type=ndk_32 -Pversion_code=121 -Pversion_name=hah

这样打包的时分就无需修正 gradle 脚本,直接经过传参的方法打包即可,做到了真正的自动化。

4、打包脚本 autopackage 的一些更新

经过上述装备之后,我对 autopackage 打包脚本也相应地做了一些调整。

1、调用脚本的时分也支持外部传入参数,比方

python run.py -s config/config_product.yml -v 324 -n 3.8.1.2

用来指定打包的装备文件、版别号以及版别称号。其次对打包脚本的 NDK 和 Flavor 装备做了调整,本次运用枚举来声明,意义愈加精确,

def assemble(bit: BitConfiguration, flavor: FlavorConfiguration) -> ApkInfo:
    '''Assemble APK with bit and flavor and copy APK and mapping files to destination.''' 
    # ./gradlew assembleNationalDebug -Pbuild_ndk_type=ndk_32 -Pversion_code=322 -Pversion_name=3.8.0
    assemble_command = "cd %s && gradlew clean %s -Pbuild_ndk_type=%s" \
        % (config.gradlew_location, flavor.get_gradlew_command(), bit.get_gradlew_bit_param_value())
    if len(build_config.version_code) != 0:
        assemble_command = assemble_command + " -Pversion_code=" + build_config.version_code
    if len(build_config.version_name) != 0:
        assemble_command = assemble_command + " -Pversion_name=" + build_config.version_name
    logi("Final gradlew command is [%s]" % assemble_command)
    os.system(assemble_command)
    info = _find_apk_under_given_directory(bit, flavor)
    _copy_apk_to_directory(info)
    _copy_mapping_file_to_directory(info, flavor)
    return info

2、对 YAML 文件解析做了简化,调用方法将愈加快捷,

class GlobalConfig:
    def parse(self):
        self._configurations = read_yaml(build_config.target_script)
        self.publish_telegram_token = self._read_key('publish.telegram.token')
    def _read_key(self, key: str):
        '''Read key from configurations.'''
        parts = key.split('.')
        value = self._configurations
        for part in parts:
            value = value[part.strip()]
        return value

3、生成 Git log 运用了规范的 Git 指令

首要,获取当时最新的 Git tag 运用了 Git 自带的指令,

git describe --abbrev=0 --tags

该指令能够以简略的方法输出最新的 tag 的称号。

此外,拿到了上述 tag 之后咱们就能够自动获取提交到上一次提交之间的所有提交记载的信息。获取提交记载的指令也运用了 Git 自带的指令,

git log %s..HEAD --oneline

上述方法能够以更见简练的代码完成自动生成当时版别 Git 改变日志的功用。

4、对 diff 输出的成果的展现进行了美化

之前发送邮件的时分运用的是纯文本,由于邮件系统的文字并不是等宽的,所以,导致了展现的时分格式化十分丑陋。本次运用了等宽的字体而且以 html 的方法发送邮件,相对来说输出的成果可视化程度更好了一些,

多渠道打包配置和打包脚本修改

以上就是脚本的更新,库房地址是 github.com/Shouheng88/… 有兴趣自己参考。