安卓多渠道配置与打包

原理与介绍

从 Flutter v1.17 开始,Flutter 命令工具增加了自定义参数的功能 --dart-define,我们可以用这个命令参数在打包或运行 App 时设置参数。这样我们就能在Flutter代码和原生代码中获取传过来的参数,从而实现多渠道功能。如:

flutter run --dart-define=CHANNEL=YYB

一、Flutter代码配置

1、获取参数

配置文件路径:lib/main.dart

/// 定义环境变量配置
class EnvironmentConfig {
  static const CHANNEL = String.fromEnvironment('CHANNEL');
}

2、任意的地方使用参数

  String currentChannel = "";

  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    // 获取 CHANNEL 参数值
    String channel = EnvironmentConfig.CHANNEL;
    print("channel:${channel}");
    currentChannel = channel;
  }

二、Android代码配置

1、获取参数

配置文件路径:android/app/build.gradle


/// 获取渠道参数使用,这里设置一下默认值
def dartEnvironmentVariables = [
        CHANNEL: 'YYB',
]

if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
            .split(',')
            .collectEntries { entry ->
                def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
                [(pair.first()): pair.last()]
            }
}

2、使用

配置文件路径:android/app/build.gradle

ext {
    publishName = '您的应用名称'
}

android {
    android.applicationVariants.all {variant ->
        variant.outputs.all {
            def buildTime = new Date().format('yyyyMMddHHmm')
            outputFileName = "${project.publishName}_${variant.versionName}_${variant.versionCode}_${buildTime}_${variant.buildType.name}_${dartEnvironmentVariables.CHANNEL}.apk"
        }
    }
}

完整的 android/app/build.gradle 配置:

def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))



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'
}



/// 获取渠道参数使用,这里设置一下默认值
def dartEnvironmentVariables = [
        CHANNEL: 'qq',
]

if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
            .split(',')
            .collectEntries { entry ->
                def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
                [(pair.first()): pair.last()]
            }
}

ext {
    publishName = '您的应用名称'
}



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


android {
    compileSdkVersion 34
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.tangzhuan.find.merchant"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
        minSdkVersion 21
        targetSdkVersion 33
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
        }
    }

    buildTypes {
        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

            minifyEnabled false 
            shrinkResources false 
        }
    }



    android.applicationVariants.all {variant ->
        variant.outputs.all {
            def buildTime = new Date().format('yyyyMMddHHmm')
            outputFileName = "${project.publishName}_${variant.versionName}_${variant.versionCode}_${buildTime}_${variant.buildType.name}_${dartEnvironmentVariables.CHANNEL}.apk"
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation 'com.amap.api:3dmap:latest.integration'
    api 'com.tencent.mm.opensdk:wechat-sdk-android:+'
    
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

三、多渠道调试与打包指令

# 调试例子1:设置渠道为应用宝。
flutter run --dart-define=CHANNEL=YYB

# 调试例子2:设置渠道为应用宝。DEBUG参数是Y
flutter run --dart-define=CHANNEL=YYB --dart-define=DEBUG=Y

#打包例子1:打包应用宝渠道包
flutter build apk --dart-define=CHANNEL=YYB

#打包例子2:打包应用宝渠道包,DEBUG参数是Y
flutter build apk --dart-define=CHANNEL=YYB --dart-define=DEBUG=Y

四、安卓一键打包脚本

1、简单介绍

通过上面的配置和优化后我们就能开始执行脚本打包了,本脚本主要实现了以下功能

1、可控制是否执行 flutter clean 清理指令(回车或者5秒无指令输入默认不清理)

2、可控制只打某个渠道包或者全部渠道包(回车或者5秒无指令输入默认打全部包)

3、可设置渠道种类数组,可无限扩展

4、成功打包后自动打开文件夹

5、实现无人值守打包

2、项目路径结构

1、shell 目录存放脚本和plist文件, pipa.sh 是苹果脚本

2、prod 目录导出打包文件,prod目录下再创建apk目录,用于存放打包的渠道apk文件

3、papk.sh 多渠道打包脚本

#!/bin/sh

#---------------------请修改渠道数组----------------#
channels=(YYB HUAWEI MI OPPO VIVO)

#当前工程绝对路径
project_path=$(pwd)

#安卓包product文件夹路径
prod_path=${project_path}/prod/apk/
#Flutter打包生成的最初地址
release_path=${project_path}/build/app/outputs/apk/release/

clean_tips="执行flutter clean(默认:n) [ y/n ]"
echo $clean_tips
read  -t 5 is_clean
if [  ! -n "${is_clean}" ];then
	is_clean="n"
fi
while([[ $is_clean != "y" ]] && [[ $is_clean != "n" ]])
do
  echo "错误!只能输入[ y/n ] !!!"
  echo $clean_tips
  read is_clean
done

tips="请输入选择渠道(默认:0) [ ALL: 0 "
c_length=${#channels[@]};
for(( i=0; i<$c_length; i++)) do
  if (($i < $c_length-1 )); then
    tips="${tips}${channels[i]}: $((i+1)) "
  else
    tips="${tips}${channels[i]}: $((i+1)) ]"
  fi
done;

echo $tips
read  -t 5 number
if [  ! -n "${number}" ];then
	number=0
fi
while(( $number < "0" || $number > $c_length ))
do
  echo "错误!只能输入0到${c_length} !!!"
  echo $tips
  read number
done

#如果有product/apk文件夹则删除,然后再创建一个空文件夹
if [ -d ${prod_path} ]; then
  rm -rf ${prod_path}
fi
#创建目录
mkdir -p ${prod_path}

if [ ${is_clean} = "y" ];then
  echo "=============== 开始清理 ==============="
	flutter clean
fi

if (($number == 0 )); then
  echo "=============== 开始构建:全部渠道包 ==============="
  for(( i=0;i<${c_length};i++)) do
    echo "正在构建:${channels[$i]} 渠道包"
    flutter build apk --no-shrink --dart-define=CHANNEL=${channels[$i]}
    cp -R ${release_path}*.apk ${prod_path}
  done;
else
  echo "=============== 正在构建:${channels[$((number-1))]} 渠道包 ==============="
  flutter build apk --no-shrink --dart-define=CHANNEL=${channels[$((number-1))]}
  cp -R ${release_path}*.apk ${prod_path}
fi

#判断apk目录下是否有文件
if [ "$(ls -A $prod_path)" ]; then
  echo "=============== APK包已导出:$prod_path ==============="
  open $prod_path
else
  echo '=============== APK包导出失败 ==============='
  exit 1
fi
exit 0

4、脚本使用

项目根目录执行命令进行多渠道打包:./shell/papk.sh

第一次可能会提示没有权限,项目根目录执行命令添加执行权限: chmod u+x shell/papk.sh

在prod/apk目录下,可以看到打包的apk:

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值