Flutter - 安卓一次打包不同包名的apk

news2024/11/14 5:44:30

demo 地址: https://github.com/iotjin/jh_flutter_demo
代码不定时更新,请前往github查看最新代码

有时为了方便测试,同一个app需要在一个手机上装两个,直接改包名的话比较麻烦,这时可以通过添加flavor进行多维度打包,同一份代码可以设置不同的包名,app应用名称和应用图标

效果图

请添加图片描述

flutter 一键打出不同包名、应用名、版本名、签名、应用图标、版本号的安装包
Android Studio 一个工程打包多个不同包名的APK
Android Gradle —— flavorDimensions 与 productFlavors

配置

需要修改的文件有两个,一个是 android/app/build.gradle ,一个是 android/app/src/main/AndroidManifest.xml

在这里插入图片描述

productFlavors 配置

核心代码是在 build.gradle添加 productFlavors 配置


 flavorDimensions("default") // 定义一个维度,这个维度的名字叫default,和下面的productFlavors中的dimension "default"对应
    productFlavors {
        // app1 | dev
        app1 {
            dimension "default"
            // 设置applicationId(这里很重要,两个相同applicationId的apk不能同时安装在同一台Android手机中)
            // applicationId "com.jh.demo1"
            applicationId "${defaultConfig.applicationId}.dev"
            // 自动生成@string/app_name为demo 把AndroidManifest.xml中的 android:label="demo"替换成 android:label="@string/app_name"
            // resValue "string", "app_name", "jh-demo1"
            // 定义app_icon字段,在AndroidManifest.xml文件中用到
            manifestPlaceholders = [
                    app_name: "jh-demo1",
                    app_icon: "@mipmap/ic_launcher",
            ]
        }
        // app2 | prod
        app2 {
            dimension "default"
            // applicationId "com.jh.demo2"
            applicationId "${defaultConfig.applicationId}"
            // resValue "string", "app_name", "jh-demo2"
            manifestPlaceholders = [
                    app_name: "jh-demo2",
                    app_icon: "@mipmap/ic_launcher",
            ]
        }
    }

然后需要在 AndroidManifest.xmlandroid:iconandroid:label换成上面配置的app_nameapp_icon
替换前:

    <application
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher"
        android:label="jh_flutter_demo">

替换后:

        <application
            android:name="${applicationName}"
            android:icon="${app_icon}"
            android:label="${app_name}">

新的编译和打包命令

加入flavor 后,按原来的方式调试运行或者打包会报错

编译:

 flutter run --flavor app1 -t lib/main.dart

打包:

flutter build apk --flavor app1
添加flavor后编译报错
     需要在 编辑器顶部 Run/Debug Configuration 里面 build flavors 设置对应的flavor 如 app1

    编译运行命令
        flutter run --flavor app1 -t lib/main.dart

    打包命令
        flutter build apk --flavor app1 --release
        flutter build apk --release --flavor app1 --target-platform=android-arm64

    清除build缓存并且打包app1和app2的debug和release包
    flutter clean; flutter build apk --flavor app1 --debug; flutter build apk --flavor app1 --release; flutter build apk --flavor app2 --debug; flutter build apk --flavor app2 --release


     查看包名
       aapt dump badging D:\apk\xxx.apk | findstr package
       package: name='com.jh.jh_flutter_demo.dev' versionCode='6' versionName='3.16.0'

       aapt dump badging D:\apk\xxx.apk

     安裝apk
       adb install -r D:\apk\xxx.apk

点击run 按钮运行需要配置下图:
在这里插入图片描述
在这里插入图片描述

打包报错 可以添加下面代码

请添加图片描述

  lintOptions {
        //在打包Release版本的时候不进行检测
        checkReleaseBuilds false
        // 有报错也不会停止打包
        abortOnError false
        // 防止报错:Error: The resource string/app_name has not been translated
        disable 'InvalidPackage'
    }
//    https://github.com/flutter/flutter/issues/58247
//    https://issuetracker.google.com/issues/158753935

完整build.gradle代码

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('app/key/key.properties')  // 上面放置的路径
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    compileSdkVersion 33

    lintOptions {
        disable 'InvalidPackage'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.jh.jh_flutter_demo"
        minSdkVersion 21
        targetSdkVersion 33
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
        ndk {
            abiFilters  'armeabi-v7a', 'arm64-v8a', 'x86_64' // 'armeabi','x86'
        }
    }

    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
            // v1SigningEnabled true
            // v2SigningEnabled true
        }
    }

    buildTypes {
//        debug {
//            signingConfig signingConfigs.release
//        }
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.release
        }
    }

    /*
     一次打包不同的apk

     添加flavor后编译报错
     需要在 编辑器顶部 Run/Debug Configuration 里面 build flavors 设置对应的flavor 如 app1

    编译运行命令
        flutter run --flavor app1 -t lib/main.dart

    打包命令
        flutter build apk --flavor app1 --release
        flutter build apk --release --flavor app1 --target-platform=android-arm64

    清除build缓存并且打包app1和app2的debug和release包
    flutter clean; flutter build apk --flavor app1 --debug; flutter build apk --flavor app1 --release; flutter build apk --flavor app2 --debug; flutter build apk --flavor app2 --release


     查看包名
       aapt dump badging D:\apk\xxx.apk | findstr package
       package: name='com.jh.jh_flutter_demo.dev' versionCode='6' versionName='3.16.0'

       aapt dump badging D:\apk\xxx.apk

     安裝apk
       adb install -r D:\apk\xxx.apk


     */

    flavorDimensions("default") // 定义一个维度,这个维度的名字叫default,和下面的productFlavors中的dimension "default"对应
    productFlavors {
        // app1 | dev
        app1 {
            dimension "default"
            // 设置applicationId(这里很重要,两个相同applicationId的apk不能同时安装在同一台Android手机中)
            // applicationId "com.jh.demo1"
            applicationId "${defaultConfig.applicationId}.dev"
            // 自动生成@string/app_name为demo 把AndroidManifest.xml中的 android:label="demo"替换成 android:label="@string/app_name"
            // resValue "string", "app_name", "jh-demo1"
            // 定义app_icon字段,在AndroidManifest.xml文件中用到
            manifestPlaceholders = [
                    app_name: "jh-demo1",
                    app_icon: "@mipmap/ic_launcher",
            ]
        }
        // app2 | prod
        app2 {
            dimension "default"
            // applicationId "com.jh.demo2"
            applicationId "${defaultConfig.applicationId}"
            // resValue "string", "app_name", "jh-demo2"
            manifestPlaceholders = [
                    app_name: "jh-demo2",
                    app_icon: "@mipmap/ic_launcher",
            ]
        }
    }

//    lintOptions {
//        //在打包Release版本的时候不进行检测
//        checkReleaseBuilds false
//        // 有报错也不会停止打包
//        abortOnError false
//        // 防止报错:Error: The resource string/app_name has not been translated
//        disable 'InvalidPackage'
//    }

//    https://github.com/flutter/flutter/issues/58247
//    https://issuetracker.google.com/issues/158753935

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }

}

flutter {
    source '../..'
}

dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1944154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

wkhtmltopdf 工具安装与使用

前情提要&#xff1a; 最近一个同事请叫我一个问题&#xff0c;他发现一片不错的博文&#xff0c;是在博客园的&#xff0c;但是不能下载这篇文章&#xff0c;我看了一下才发现&#xff0c;原来csdn也是不行的。合理。毕竟是人家辛苦写的文章&#xff0c;不能就这么被别人随便c…

ipsec VPN设备在边界情况

目录 ipsec VPN设备在边界情况 基础配置 AR1 AR2 AR3 PC 边界路由器通测试 IPSEC VPN配置 1.抓流量 AR1 AR3 2.配置IKE的安全提议&#xff08;五元组&#xff09; AR1 AR3 3.配置IKE对等体 AR1 AR2 4.配置IPSEC安全提议 AR1 AR3 5.配置IPSEC的安全策略 AR…

css黑色二级下拉导航菜单

黑色二级下拉导航菜单https://www.bootstrapmb.com/item/14816 body { font-family: Arial, sans-serif; margin: 0; padding: 0; }nav { background-color: #000; /* 导航背景色为黑色 */ }.menu { list-style-type: none; margin: 0; padding: 0; overflow: hidden; }.menu l…

昇思25天学习打卡营第18天|生成式-GAN图像生成

打卡 目录 打卡 GAN 博弈函数 博弈过程 GAN 案例 数据集 数据加载与可视化 隐码构造 模型构建 生成器 判别器 损失函数和优化器 模型训练 输出展示-1w张训练样本 输出展示-6w张训练样本 输出展示-6w张-100 epoch 效果展示 部分展示如图-12epoch-6w张 部分展…

html+css前端作业 王者荣耀官网6个页面无js

htmlcss前端作业 王者荣耀官网6个页面无js 下载地址 https://download.csdn.net/download/qq_42431718/89571150 目录1 目录2 项目视频 王者荣耀6个页面&#xff08;无js&#xff09; 页面1 页面2 页面3 页面4 页面5 页面6

3.1 FreeRTOS详细移植步骤(自己的实操)

[TOC](3.1 FreeRTOS详细移植步骤(自己的实操)) 自己使用阿波罗F767的内存管理实验和定时器实验&#xff0c;进行复刻。 FreeRTOS源码版本是FreeRTOS 202212.01。官网和Github都有下载。 按照STM32F767FreeRTOS开发手册V1.1进行移植复刻。 注:这个开发手册不是开发指南。跟视频里…

小程序多排数据横向滚动实现

如何实现多排数据滚动效果 swiper 外部容器 swiper-item 每一页的数据 因为现在有多排数据,现在在swiper-item 中需要循环一个数组 初版 <template><view><view class"container"><view class"swiper-box"><swiper class&qu…

ubuntu 22.04 安装部署gitlab详细过程

目录 gitlab介绍 gitlab安装 步骤1&#xff1a;更新系统 步骤2&#xff1a;添加 GitLab 的 GPG 密钥 gitlab企业版 gitlab社区版 步骤3&#xff1a;安装 GitLab 社区版 社区版 步骤4&#xff1a;初始化 GitLab 步骤5&#xff1a;访问 GitLab 步骤6&#xff1a;查看r…

mybatis中的缓存(一级缓存、二级缓存)

文章目录 前言一、MyBatis 缓存概述二、一级缓存1_初识一级缓存2_一级缓存命中原则1_StatementId相同2_查询参数相同3_分页参数相同4_sql 语句5_环境 3_一级缓存的生命周期1_缓存的产生2_缓存的销毁3_网传的一些谣言 4_一级缓存核心源码5_总结 三、二级缓存1_开启二级缓存2_二级…

# OpenCV 图像预处理—形态学:膨胀、腐蚀、开运算、闭运算 原理详解

文章目录 形态学概念膨胀使用膨胀操作来修复裂痕示例代码关键解析&#xff1a; 腐蚀使用腐蚀操作消除噪点示例代码&#xff1a; 开运算—先腐蚀后膨胀闭运算—先膨胀后腐蚀 形态学概念 首先看这两张图片 一张图周围有大大小小的噪音和彩点&#xff0c;另一张图片中字母有间隙&…

安宝特方案|解放双手,解决死角,AR带来质量监督新体验

AR质量监督 解放双手&#xff0c;解决死角 在当今制造业快速发展的背景下&#xff0c;质量监督成为确保产品高质量和完善的管理制度的关键环节。然而&#xff0c;传统的质量监督方式存在诸多挑战&#xff0c;如人工操作带来的效率低下、查岗不及时、摄像头死角等问题。 为了解…

el-upload照片墙自定义上传多张图片(手动一次性上传多张图片)包含图片回显,删除

需求&#xff1a;el-upload照片墙自定义上传多张图片&#xff08;手动一次性上传多张图片&#xff09;包含图片回显&#xff0c;删除&#xff0c;预览&#xff0c;在网上看了很多&#xff0c;都没有说怎么把数据转为file格式的&#xff0c;找了很久最终实现&#xff0c; 难点&a…

Java之数组应用-选择排序-插入排序

已经完全掌握了冒泡排序和二分查找的同学&#xff0c;可以自己尝试学习选择、插入排序。不要求今天全部掌握&#xff0c;最近2-3天掌握即可&#xff01; 1 选择排序 选择排序(Selection Sort)的原理有点类似插入排序&#xff0c;也分已排序区间和未排序区间。但是选择排序每次…

《峡谷小狐仙-多模态角色扮演游戏助手》复现流程

YongXie66/Honor-of-Kings_RolePlay: The Role Playing Project of Honor-of-Kings Based on LnternLM2。峡谷小狐仙--王者荣耀领域的角色扮演聊天机器人&#xff0c;结合多模态技术将英雄妲己的形象带入大模型中。 (github.com) https://github.com/chg0901/Honor_of_Kings…

盘点2024年大家都在使用的AI智能写作工具

在科技发达的现在社会&#xff0c;AI已经悄悄的渗入我们生活的各种角落。不知道你有没有尝试过用ai智能写作来完成一些文章创作呢&#xff1f;这次我介绍几个可以提升效率的ai智能写作工具给你试试吧。 1.笔&#xff5c;灵AI写作 CSDN 传送门&#xff1a;https://ibiling.cn…

Interesting bug caused by getattr

题意&#xff1a;由 getattr 引起的有趣的 bug 问题背景&#xff1a; I try to train 8 CNN models with the same structures simultaneously. After training a model on a batch, I need to synchronize the weights of the feature extraction layers in other 7 models. …

Vue3+Element Plus 实现table表格中input的验证

实现效果 html部分 <template><div class"table"><el-form ref"tableFormRef" :model"form"><el-table :data"form.detailList"><el-table-column type"selection" width"55" align&…

初识c++(string和模拟实现string)

一、标准库中的string类 string类的文档介绍&#xff1a;cplusplus.com/reference/string/string/?kwstring 1、auto和范围for auto&#xff1a; 在早期C/C中auto的含义是&#xff1a;使用auto修饰的变量&#xff0c;是具有自动存储器的局部变量&#xff0c;后来这个 不重…

【北航主办丨本届SPIE独立出版丨已确认ISSN号】第三届智能机械与人机交互技术学术会议(IHCIT 2024,7月27)

由北京航空航天大学指导&#xff0c;北京航空航天大学自动化科学与电气工程学院主办&#xff0c;AEIC学术交流中心承办的第三届智能机械与人机交互技术学术会议&#xff08;IHCIT 2024&#xff09;将定于2024年7月27日于中国杭州召开。 大会面向基础与前沿、学科与产业&#xf…

初识c++:string类 (1)

目录 # 初识c&#xff1a;string类 1.为什么学习string类 2.标准库中的string类 2.1 string类的了解 2.2 auto和范围for 2.3 string类的常用接口说明 2.3.1string类对象的常见构造 2.3.2string类对象的容量操作 2.3.3string类对象的访问及遍历操作 2.3.4string类对象…