android 多渠道打包

发布时间:2026/10/6 7:57:18
android 多渠道打包 有这样的需求 应用上架googlePlay权限审批没通过需要分为两个版本normal版本升级方案为原有的升级方案 调用安装新版本apk需要 android.permission.REQUEST_INSTALL_PACKAGES 这个权限。 而Google Play升级不能有这个权限需要去掉这个权限。 所以需要打两个渠道包一个normal版本一个Google Play版本。app/build.gradle.kts中增加如下渠道配置另外 Google play升级的依赖app/build.gradle.kts完整代码如下plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.compose) } android { // 1. 定义维度名称。 // flavorDimensions用于声明有哪些分类维度它将所有的 productFlavors 划分为不同的组。每个组代表一个独立的维度。 flavorDimensions app_channel // 2. 配置产品变种 productFlavors { create(normal) { // dimension 是在具体的 productFlavor 内部使用的属性用于指定当前这个 Flavor ‌属于‌哪一个预先声明好的维度 dimension app_channel // 注意buildConfigField 的参数类型和值需要符合 Kotlin 字符串规范 // false 是字符串类型的值传递给 Java/Kotlin 代码时会变成 boolean false buildConfigField(boolean, IS_GOOGLE_PLAY, false) } create(googlePlay) { dimension app_channel buildConfigField(boolean, IS_GOOGLE_PLAY, true) } } // 在这里添加配置开启 BuildConfig 自动生成 buildFeatures { buildConfig true } namespace com.example.androiddemos compileSdk { version release(36) } ndkVersion 28.2.13676358 externalNativeBuild { cmake { path file(src/main/cpp/CMakeLists.txt) version 3.22.1 } } defaultConfig { applicationId com.example.androiddemos minSdk 29 targetSdk 36 versionCode 1 versionName 1.0 testInstrumentationRunner androidx.test.runner.AndroidJUnitRunner ndk { abiFilters.addAll(listOf(arm64-v8a, armeabi-v7a)) } } buildTypes { release { isMinifyEnabled false proguardFiles( getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro ) } } compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 } buildFeatures { compose true } } dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.material3) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.compose.ui.test.junit4) debugImplementation(libs.androidx.compose.ui.tooling) debugImplementation(libs.androidx.compose.ui.test.manifest) implementation(androidx.appcompat:appcompat:1.6.1) implementation(androidx.constraintlayout:constraintlayout:2.2.1) implementation(androidx.camera:camera-core:1.4.0) implementation(androidx.camera:camera-camera2:1.4.0) implementation(androidx.camera:camera-lifecycle:1.4.0) implementation(androidx.camera:camera-view:1.4.0) // implementation(androidx.camera:camera-view-ktx:1.4.0) // 仅 googlePlay 渠道编译时包含此依赖. 前面是渠道名如果仅normal渠道包含某依赖则写normalImplementation(...) googlePlayImplementation(com.google.android.play:app-update:2.1.0) // 如果用 Kotlin 扩展库也同理 googlePlayImplementation(com.google.android.play:app-update-ktx:2.1.0) }main资源目录的一个包里面新增统一的升级接口package com.example.androiddemos.update import android.app.Activity /** * 检查版本升级 */ interface IUpdateChecker { fun check(activity: Activity) }新增Google play渠道资源目录并在其中新增升级实现类以及AndroidManifest文件其中AndroidManifest内容如下?xml version1.0 encodingutf-8? manifest xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:toolshttp://schemas.android.com/tools !-- 强制移除该权限防止AAR/sdk依赖带入REQUEST_INSTALL_PACKAGESGP上架保护 -- uses-permission android:nameandroid.permission.REQUEST_INSTALL_PACKAGES tools:noderemove / /manifestUpdaterImpl代码如下package com.example.androiddemos.update import android.app.Activity import android.app.AlertDialog import android.util.Log import com.example.androiddemos.MainActivity import com.google.android.play.core.appupdate.AppUpdateManagerFactory import com.google.android.play.core.appupdate.AppUpdateOptions import com.google.android.play.core.install.model.AppUpdateType import com.google.android.play.core.install.model.UpdateAvailability class UpdaterImpl(private val activity: Activity) : IUpdateChecker { override fun check(activity: Activity) { Log.d(Updater, google play channel check update) val appUpdateManager AppUpdateManagerFactory.create(activity) appUpdateManager.appUpdateInfo.addOnSuccessListener { info - if (info.updateAvailability() UpdateAvailability.UPDATE_AVAILABLE info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) ) { // 弹框 AlertDialog.Builder(activity) .setTitle(发现新版本) .setMessage(检测到新版本是否立即更新) .setPositiveButton(确定) { _, _ - val options AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build() appUpdateManager.startUpdateFlowForResult( info, activity, options, MainActivity.REQUEST_CODE_GP_UPDATE ) } .setNegativeButton(取消, null) .show() } }.addOnFailureListener { e - Log.e(Update, GP check failed, e) } } }MainActivity加上常量 REQUEST_CODE_GP_UPDATE以及onActivityResult响应升级结果这个是按钮点击就调用UpdaterImpl的check方法检查版本升级同样normal渠道包也是新建以下同样结构注意UpdaterImpl的类名以及包名需要和Google play渠道的完全一致否则编译不过 其中AndroidManifest内容如下?xml version1.0 encodingutf-8? manifest xmlns:androidhttp://schemas.android.com/apk/res/android uses-permission android:nameandroid.permission.REQUEST_INSTALL_PACKAGES / /manifestUpdaterImpl代码如下package com.example.androiddemos.update import android.app.Activity import android.util.Log class UpdaterImpl(private val activity: Activity) : IUpdateChecker { override fun check(activity: Activity) { // 使用非GP的更新逻辑 Log.d(Updater, Normal channel does not support in-app updates) // 待实现 ... ... } }ok. 开始打Google play渠道包运行点击检查升级日志D google play channel check update 2026-10-05 20:58:48.681 15900-15900 PlayCore com.example.androiddemos E UID: [10404] PID: [15900] AppUpdateService : onError(-9) 2026-10-05 20:58:48.695 15900-15900 Update com.example.androiddemos E GP check failed com.google.android.play.core.install.InstallException: -9: Install Error(-9): The Play Store app is either not installed or not the official version. (https://developer.android.com/reference/com/google/android/play/core/install/model/InstallErrorCode#ERROR_PLAY_STORE_NOT_FOUND) at com.google.android.play.core.appupdate.zzr.zzj(com.google.android.play:app-update2.1.0:2) at com.google.android.play.core.appupdate.zzr.zze(com.google.android.play:app-update2.1.0:1) at com.google.android.play.core.appupdate.zzg.getAppUpdateInfo(com.google.android.play:app-update2.1.0:1) at com.example.androiddemos.update.UpdaterImpl.check(UpdaterImpl.kt:16) at com.example.androiddemos.MainActivityKt.Greeting$lambda$6$lambda$5$lambda$4(MainActivity.kt:92) at com.example.androiddemos.MainActivityKt$$ExternalSyntheticLambda3.invoke(D8$$SyntheticClass:0) at androidx.compose.foundation.ClickableNode.onPointerEvent-H0pRuoY(Clickable.kt:1009) at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:436) at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:422) at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:275) at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:171) at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:118) at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:2428) at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:2378) at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:2249) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3343) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3004) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3343) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3004) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3343) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3004) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3343) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3004) at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:898) at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:2077) at android.app.Activity.dispatchTouchEvent(Activity.java:4516) at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:817) at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:805) at android.view.View.dispatchPointerEvent(View.java:15273) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:8511) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:8245) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7594) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7651) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7617) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:7799) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7625) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:7856) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7598) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7651) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7617) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7625) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7598) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:11132) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:11034) 2026-10-05 20:58:48.695 15900-15900 Update com.example.androiddemos E at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:10987) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:11385) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:310) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:374) at android.os.Looper.loopOnce(Looper.java:163) at android.os.Looper.loop(Looper.java:293) at android.app.ActivityThread.loopProcess(ActivityThread.java:10170) at android.app.ActivityThread.main(ActivityThread.java:10159) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1247)异常意思是没安装Google应用商店。环境准备好才能正常检查升级。再看下apk其中没有 REQUEST_INSTALL_PACKAGES 权限同理打下normal包看下ok。有安装apk权限。 运行点击检查升级ok.