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

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 | devapp1 {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 | prodapp2 {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
替换前:

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

替换后:

        <applicationandroid: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 --releaseflutter 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 packagepackage: name='com.jh.jh_flutter_demo.dev' versionCode='6' versionName='3.16.0'aapt dump badging D:\apk\xxx.apk安裝apkadb install -r D:\apk\xxx.apk

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

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

请添加图片描述

  lintOptions {//在打包Release版本的时候不进行检测checkReleaseBuilds false// 有报错也不会停止打包abortOnError false// 防止报错:Error: The resource string/app_name has not been translateddisable '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 33lintOptions {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 21targetSdkVersion 33versionCode flutterVersionCode.toInteger()versionName flutterVersionNametestInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"multiDexEnabled true}signingConfigs {release {keyAlias keystoreProperties['keyAlias']keyPassword keystoreProperties['keyPassword']storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : nullstorePassword 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.releasendk {abiFilters  'armeabi-v7a', 'arm64-v8a', 'x86_64' // 'armeabi','x86'}}}/*一次打包不同的apk添加flavor后编译报错需要在 编辑器顶部 Run/Debug Configuration 里面 build flavors 设置对应的flavor 如 app1编译运行命令flutter run --flavor app1 -t lib/main.dart打包命令flutter build apk --flavor app1 --releaseflutter 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 packagepackage: name='com.jh.jh_flutter_demo.dev' versionCode='6' versionName='3.16.0'aapt dump badging D:\apk\xxx.apk安裝apkadb install -r D:\apk\xxx.apk*/flavorDimensions("default") // 定义一个维度,这个维度的名字叫default,和下面的productFlavors中的dimension "default"对应productFlavors {// app1 | devapp1 {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 | prodapp2 {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/158753935compileOptions {sourceCompatibility JavaVersion.VERSION_11targetCompatibility 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.mzph.cn/diannao/50663.shtml

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

相关文章

Flink入门(更新中)

目录 一、Flink 1.1 基本概念 1.1.1 flink简介 1.2 flink编程模版 1.3 常用概念 1.2.1 datastream 1.2.2 算子、Task 1.2.3 多流操作 1.2.6 时间语义 二、Flink编程实战(Java) 2.1 wordcount 一、Flink 1.1 基本概念 1.1.1 flink简介 1.图片介绍 性能&#xff1a…

OpenAI推出SearchGPT:革新搜索体验的新工具

引言 原文链接 在信息爆炸的时代&#xff0c;搜索引擎已经成为人们日常生活中不可或缺的工具。然而&#xff0c;传统的搜索引擎在理解复杂查询和提供准确答案方面仍有许多不足。为了解决这一问题&#xff0c;OpenAI与20240725推出了SearchGPT原型&#xff0c;将生成式AI与传统…

kafka源码阅读-ReplicaStateMachine(副本状态机)解析

概述 Kafka源码包含多个模块&#xff0c;每个模块负责不同的功能。以下是一些核心模块及其功能的概述&#xff1a; 服务端源码 &#xff1a;实现Kafka Broker的核心功能&#xff0c;包括日志存储、控制器、协调器、元数据管理及状态机管理、延迟机制、消费者组管理、高并发网络…

Vue常用指令及其生命周期

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 目录 1.常用指令 1.1 v-bind 1.2 v-model 注意事项 1.3 v-on 注意事项 1.4 v-if / v-else-if / v-else 1.5 v-show 1.6 v-for 无索引 有索引 生命周期 定义 流程 1.常用指令 Vue当中的指令…

远程项目调试-informer2020

informer2020 Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting(原文&#xff09;Informer 是一个基于Transformer的模型&#xff0c;是为了应对长依赖关系而开发的。本文的主要主题是序列预测。序列预测可以在任何具有不断变化的数据的地方…

Linux——管理本地用户和组(详细介绍了Linux中用户和组的概念及用法)

目录 一、用户和组概念 &#xff08;一&#xff09;、用户的概念 &#xff08;二&#xff09;、组的概念 补充组 主要组 二、获取超级用户访问权限 &#xff08;一&#xff09;、su 命令和su -命令 &#xff08; 二&#xff09;、sudo命令 三、管理本地用户账户 &…

ERROR: Cannot find command ‘git’- do you have ‘git’ installed and in your PATH?

ERROR: Cannot find command ‘git’- do you have ‘git’ installed and in your PATH? 目录 ERROR: Cannot find command ‘git’- do you have ‘git’ installed and in your PATH? 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/61780…

Transformer自然语言处理实战pdf阅读

一.第一章 欢迎来到transformer的世界 1.解码器-编码器框架 在Transformer出现之前&#xff0c;NLP的最新技术是LSTM等循环架构。这些架 构通过在神经网络连接使用反馈循环&#xff0c;允许信息从一步传播到另一 步&#xff0c;使其成为对文本等序列数据进行建模的理想选择。如…

多模态大模型应用中的Q-Former是什么?

多模态大模型应用中的Q-Former是什么&#xff1f; Q-Former是一种新型的神经网络架构&#xff0c;专注于通过查询&#xff08;Query&#xff09;机制来改进信息检索和表示学习。在这篇博客中&#xff0c;我们将详细探讨Q-Former的工作原理、应用场景&#xff0c;并在必要时通过…

pyqt designer使用spliter

1、在designer界面需要使用spliter需要父界面不使用布局&#xff0c;减需要分割两个模块选中&#xff0c;再点击spliter分割 2、在分割后&#xff0c;再对父界面进行布局设置 3、对于两边需要不等比列放置的&#xff0c;需要套一层 group box在最外层进行分割

大数据学习之Flink基础

Flink基础 1、系统时间与时间时间 系统时间&#xff08;处理时间&#xff09; 在Sparksreaming的任务计算时&#xff0c;使用的是系统时间。 假设所用窗口为滚动窗口&#xff0c;大小为5分钟。那么每五分钟&#xff0c;都会对接收的数据进行提交任务. 但是&#xff0c;这里有…

GoogleCTF2023 Writeup

GoogleCTF2023 Writeup Misc NPC Crypto LEAST COMMON GENOMINATOR? Web UNDER-CONSTRUCTION NPC A friend handed me this map and told me that it will lead me to the flag. It is confusing me and I don’t know how to read it, can you help me out? Attach…

VSCode切换默认终端

我的VSCode默认终端为PowerShell&#xff0c;每次新建都会自动打开PowerShell。但是我想让每次都变为cmd&#xff0c;也就是Command Prompt 更改默认终端的操作方法如下&#xff1a; 键盘调出命令面板&#xff08;CtrlShiftP&#xff09;中,输入Terminal: Select Default Prof…

Java 中的Stream流

Stream流就像工厂中的流水线操作。 如何使用Stream&#xff1f; 1、首先要获取Stream流&#xff0c;那么如何获取呢? 对于不同的数据&#xff0c;有不同的获取方法。 ①单列集合 方法名说明default Stream<E> stream()Collection接口中的默认方法 所以实现了Colle…

Multi Range Read与Covering Index是如何优化回表的?

上篇文章末尾我们提出一个问题&#xff1a;有没有什么办法可以尽量避免回表或让回表的开销变小呢&#xff1f; 本篇文章围绕这个问题提出解决方案&#xff0c;一起来看看MySQL是如何优化的 回表 为什么会发生回表&#xff1f; 因为使用的索引并没有整条记录的所有信息&…

DataEase一键部署:轻松搭建数据可视化平台

DataEase是一个开源的数据可视化和分析工具&#xff0c;旨在帮助用户轻松创建和共享数据仪表盘。它支持多种数据源&#xff0c;包括关系型数据库&#xff0c;文件数据源&#xff0c;NoSQL数据库等&#xff0c;提供强大的数据查询、处理和可视化功能。DataEase 不仅是一款数据可…

VMware虚拟机中CentOS7自定义ip地址并且固定ip

配置固定ip(虚拟机) 前提&#xff1a;虚拟机网络配置成&#xff0c;自定义网络并选择VMnet8(NAT 模式) 操作(如下图)&#xff1a;点击虚拟机–》设置–》–》硬件–》网络适配器–》自定义&#xff1a;特定虚拟网络–》选择&#xff1a;VMnet8(NAT 模式) 虚拟机网络设置 需要记…

【漏洞复现】Jenkins CLI 接口任意文件读取漏洞(CVE-2024-23897)

漏洞简介 Jenkins是一款基于JAVA开发的开源自动化服务器。 Jenkins使用args4j来解析命令行输入&#xff0c;并支持通过HTTP、WebSocket等协议远程传入命令行参数。在args4j中&#xff0c;用户可以通过字符来加载任意文件&#xff0c;这导致攻击者可以通过该特性来读取服务器上…

论文快过(图像配准|Coarse_LoFTR_TRT)|适用于移动端的LoFTR算法的改进分析 1060显卡上45fps

项目地址&#xff1a;https://github.com/Kolkir/Coarse_LoFTR_TRT 创建时间&#xff1a;2022年 相关训练数据&#xff1a;BlendedMVS LoFTR [19]是一种有效的深度学习方法&#xff0c;可以在图像对上寻找合适的局部特征匹配。本文报道了该方法在低计算性能和有限内存条件下的…

【PyTorch】基于LSTM网络的气温预测模型实现

假设CSV文件名为temperature_data.csv&#xff0c;其前五行和标题如下&#xff1a; 这里&#xff0c;我们只使用Temperature列进行单步预测。以下是整合的代码示例&#xff1a; import pandas as pd import numpy as np import torch import torch.nn as nn import torch.op…