Flutter 第三方SDK集成友盟统计(亲测有效)
echo "=============== 正在构建:${channels[$((number-1))]} 渠道包 ==============="echo "=============== APK包已导出:$prod_path ==============="echo "=============== 开始构建:全部渠道包 ==============="#-------------------
题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。
Flutter 第三方SDK集成友盟统计(亲测有效)
最近开发过程中,需要引入友盟进行统计服务。友盟统计还需要区分不同渠道的打开应用的情况,所以需要处理多渠道打包的问题。
一、引入友盟统计
在工程的pubspec.yaml中引入插件
// 在工程 pubspec.yaml 中加入
dependencies:
umeng_common_sdk: ^1.2.3
导入及调用初始化友盟
import 'package:umeng_common_sdk/umeng_common_sdk.dart';
调用友盟统计
@override
void initState() {
super.initState();
initPlatformState();
UmengCommonSdk.initCommon('5e3f96f3cb23d2a070000048', '5e3f96f3cb23d2a070000048', 'Umeng');
UmengCommonSdk.setPageCollectionModeManual();
}
这里需要填写channel渠道名后续我们需要根据打包的渠道来设置。
二、flutter代码中获取渠道
Flutter命令工具增加了自定义参数的功能 --dart-define,可以用这个命令参数在打包或运行 App 时设置参数。
如:
flutter run --dart-define=CHANNEL=YYB
在lib/main.dart中定义变量配置,可以方便调用
/// 定义环境变量配置
class EnvironmentConfig {
static const CHANNEL = String.fromEnvironment('CHANNEL');
}
在需要的地方调用获取渠道名
String currentChannel = "";
@override
void initState() {
// TODO: implement initState
super.initState();
// 获取CHANNEL 参数值
String channel = EnvironmentConfig.CHANNEL;
print("channel:${channel}");
currentChannel = channel;
setState(() {});
}
显示渠道名
Container(
height: 136,
width: 300,
color: Colors.lightGreen,
alignment: Alignment.center,
child: Text(
'当前渠道:${currentChannel}',
style: TextStyle(fontSize: 12, color: Colors.white),
),
),
最终获得渠道显示效果图如下
三、android中gradle配置
我们需要在android/app/build.gradle中添加一下配置
/// 获取渠道参数使用,这里设置一下默认值
def dartEnvironmentVariables = [
CHANNEL: 'guanfang-app',
]
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()]
}
}
在输出的apk中,添加对应渠道名,在android一下${dartEnvironmentVariables.CHANNEL}进行区分不同渠道的apk名称。
ext {
publishName = 'AppDemoLab'
}
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"
}
}
}
打包与测试命令
# 调试例子1:设置渠道为应用宝。
flutter run --dart-define=CHANNEL=YYB
#打包例子1:打包应用宝渠道包
flutter build apk --dart-define=CHANNEL=YYB
可以是多个–dart-define,如:
#打包例子2:打包应用宝渠道包,DEBUG参数是Y
flutter build apk --dart-define=CHANNEL=YYB --dart-define=DEBUG=Y
四、apk.sh多渠道打包脚本
在脚本中定义了渠道channels=(YYB HUAWEI MI OPPO VIVO)
在工程目录下创建shell目录,将apk.sh放到shell目录下。
在工程目录下创建prod目录,prod目录下创建apk目录,用于存放打包的渠道apk文件
apk.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
查看脚本可以看出
控制是否执行flutter clean
输入是全部渠道打包
打包后的apk拷贝到prod/apk文件夹下。
通过cd切换到shell目录下,执行apk.sh脚本进行多渠道打包
./shell/papk.sh
在prod/apk目录下,可以看到打包的apk
参考:https://github.com/sugood/flutter_shell
五、更改友盟渠道
在文中,使用友盟时候,需要传递渠道名,我们通过EnvironmentConfig.CHANNEL拿到渠道名后作为参数传给友盟。
友盟即可根据渠道进行统计。
六、附录(完整的gradle配置)
android/build.gradle配置如下
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
maven { url "https://maven.aliyun.com/repository/google" }
maven { url "https://maven.aliyun.com/repository/central" }
maven { url "https://maven.aliyun.com/repository/jcenter" }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
maven { url "https://maven.aliyun.com/repository/google" }
maven { url "https://maven.aliyun.com/repository/central" }
maven { url "https://maven.aliyun.com/repository/jcenter" }
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
android/app/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'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
/// 获取渠道参数使用,这里设置一下默认值
def dartEnvironmentVariables = [
CHANNEL: 'GuanFang',
]
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 = 'AppDemoLab'
}
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
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.flutter_app_demolab"
// 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 flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
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.debug
}
}
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 '../..'
}
七、小结
flutter开发实战-实现多渠道打包及友盟统计(亲测有效),根据自身需求调整后亲测有效,可以根据渠道来做一些代码上的区分。
学习记录,每天不停进步。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)