Android中的apk打包

前言

使用友盟对应用进行信息收集时,其中包含有一个渠道名。渠道姑且可以认为是一个商店吧,如果应用要在很多个商店上面上架的话,一直改太麻烦了。有一个叫做多渠道打包的东西自然而然地走了过来。

多渠道打包实现

<meta-data
    android:name="UMENG_APPKEY"
    android:value="xxxxxxxxxxxxxxxxxxxxxx" />
<meta-data
    android:name="UMENG_CHANNEL"
    android:value="Google Play Store" />

如上所示,如果需要换一个渠道的话,重新改的话就特别麻烦了。先将其中的value替换成占位符${UMENG_CHANNEL_VALUE}。接下来到模块下的build.gradle中进行相应的修改。修改大致如下:

<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_NAME}" />

接下来配置build.gradle

defaultConfig {
    ...
    // 默认是umeng的渠道
    manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng"]
}

// 友盟多渠道打包
flavorDimensions "wtf"
productFlavors{
    google {
        dimension "wtf"
    }
    coolapk {
        dimension "wtf"
    }
}

productFlavors.all { flavor ->
    flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}

自动设置应用签名

在buildType{}前添加下段,并在buildType的release中添加signingConfig signingConfigs.release

signingConfigs {
    debug {
        // No debug config
    }

    release {
        storeFile file("../yourapp.keystore")
        storePassword "your password"
        keyAlias "your alias"
        keyPassword "your password"
    }
}

打release版本的包时就会使用其中所配置的签名了。

修改AS生成的apk默认名

不同gradle版本间存在一些差异,如果报错了,google修改一下。

applicationVariants.all { variant ->
    variant.outputs.all { output ->
//                    outputFileName = new File(
//                            "JPreader-" + ${variant.productFlavors[0].name} +
//                                    buildType.name + "-v" +
//                                    defaultConfig.versionName + "-" +
//                                    defaultConfig.versionCode + ".apk" )
        if (outputFile != null && outputFile.name.endsWith('.apk')) {
            // 输出apk名称为ruijie_v1.0_wandoujia.apk
            def fileName = "JPreader_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk"
            outputFileName = new File(fileName)
        }
    }
}

小结

build.gradle真的是神奇,有一些用法还是可以去学学。当前的build.gradle文件的整体如下所示:

android {
    compileSdkVersion 26
    buildToolsVersion '26.0.2'
    defaultConfig {
        applicationId "cn.xuchuanjun.nhknews"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 2
        versionName "1.1"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//        jackOptions {
//            enabled true
//        }
        //multiDexEnable true //突破应用方法数65535的一个限制
        manifestPlaceholders=[UMENG_CHANNEL_NAME:"Google Play Store"]
    }

    signingConfigs {
        debug {

        }
        myReleaseConfig {
            storeFile file("xxxxxxxxxxxxxxxxx.jks")
            storePassword "xxxxxxxx"
            keyAlias "xxxxxx"
            keyPassword "xxxxxxxx"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.myReleaseConfig

            applicationVariants.all { variant ->
                variant.outputs.all { output ->
//                    outputFileName = new File(
//                            "JPreader-" + ${variant.productFlavors[0].name} +
//                                    buildType.name + "-v" +
//                                    defaultConfig.versionName + "-" +
//                                    defaultConfig.versionCode + ".apk" )
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 输出apk名称为ruijie_v1.0_wandoujia.apk
                        def fileName = "JPreader_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk"
                        outputFileName = new File(fileName)
                    }
                }

            }
        }
    }
    flavorDimensions "wtf"
    productFlavors{
        google {
            dimension "wtf"
        }
        coolapk {
            dimension "wtf"
        }
    }

    productFlavors.all{
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_NAME:name]
    }

    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}

Read more

Volcano 与 Kubernetes GPU 调度学习笔记

本笔记系统整理 Volcano 调度器、Kubernetes 调度框架、GPU Device Plugin、HAMi 等云原生 AI 调度领域的核心知识,适合用于学习、复习和工程实践参考。 目录 * 第一部分:Volcano 入门 * 1. Volcano 是什么 * 2. 安装与快速使用 * 3. 核心特性一览 * 第二部分:Volcano 整体架构 * 4. Volcano 解决的核心问题 * 5. 整体架构与数据流 * 6. 三层抽象模型 * 第三部分:Volcano 核心实现原理 * 7. Session 机制 * 8. Gang Scheduling 实现 * 9. Queue 与 DRF 公平调度

容器镜像(4):镜像的常用工具箱

容器镜像(4):镜像的常用工具箱

前几篇在讲多架构镜像时已经用过 skopeo 和 crane 做镜像复制,这篇系统整理这两个工具的完整能力,同时介绍几个日常操作镜像时同样好用的工具。 一、skopeo:不依赖 Daemon 的镜像瑞士军刀 skopeo 的核心价值是绕过 Docker daemon,直接与 Registry API 交互。上一篇用它做镜像复制和离线传输,但它的能力远不止于此。 1.1 安装 # Ubuntu / Debian sudo apt install -y skopeo skopeo --version # skopeo version 1.15.1 1.2 inspect:免拉取检查镜像元数据 docker inspect 需要先把镜像拉到本地,skopeo inspect 直接向 Registry

容器镜像(3):多架构镜像构建

容器镜像(3):多架构镜像构建

一、什么是多架构镜像 1.1 OCI Image Index 上一篇介绍了单平台镜像的结构:一个 Manifest 指向 Config 和若干 Layer blob。多架构镜像在此之上多了一层——OCI Image Index(也叫 Manifest List),是一个轻量的索引文件,把多个单平台 Manifest 组织在一起: $ docker manifest inspect golang:1.22-alpine { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests&

容器镜像(2):containerd 视角下的镜像

容器镜像(2):containerd 视角下的镜像

一、为什么需要了解 containerd 如果你只用 docker run 跑容器,从来不关心底层,那可以不了解 containerd。但如果你在用 Kubernetes,或者想真正理解"容器运行时"是什么,containerd 是绕不开的。 事实上,当你执行 docker run 的时候,containerd 早就在后台悄悄工作了——Docker 从 1.11 版本开始,就把核心运行时剥离出来交给 containerd 负责。 1.1 Docker 的架构演变 早期的 Docker(1.10 及之前)是一个"大一统"的单体程序:一个 dockerd