refactor: 更换包名和签名证书以绕过华为风险软件检测
## 更改内容 - 包名: com.rwadurian.rwa_android_app → com.durianqueen.app - 签名证书: 使用新的 durianqueen-release.keystore - MethodChannel: 更新为新包名前缀 ## 原因 华为应用市场 13.2+ 版本对未上架应用检测更严格, 会记录包名和签名,标记为"风险应用"。 更换包名和签名证书让华为识别为全新应用。 ## 注意 - 用户需要卸载旧版本重新安装 - 本地数据会丢失 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1dfa02b386
commit
0b3bf0ae4f
|
|
@ -49,7 +49,7 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.rwadurian.rwa_android_app"
|
namespace = "com.durianqueen.app"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId = "com.rwadurian.rwa_android_app"
|
applicationId = "com.durianqueen.app"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
|
|
|
||||||
|
|
@ -1,106 +1,106 @@
|
||||||
package com.rwadurian.rwa_android_app
|
package com.durianqueen.app
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
private val INSTALLER_CHANNEL = "com.rwadurian.app/apk_installer"
|
private val INSTALLER_CHANNEL = "com.durianqueen.app/apk_installer"
|
||||||
private val MARKET_CHANNEL = "com.rwadurian.app/app_market"
|
private val MARKET_CHANNEL = "com.durianqueen.app/app_market"
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
// Install splash screen - must be called before super.onCreate()
|
// Install splash screen - must be called before super.onCreate()
|
||||||
val splashScreen = installSplashScreen()
|
val splashScreen = installSplashScreen()
|
||||||
|
|
||||||
// Keep splash screen visible until Flutter is ready
|
// Keep splash screen visible until Flutter is ready
|
||||||
var keepSplashScreen = true
|
var keepSplashScreen = true
|
||||||
splashScreen.setKeepOnScreenCondition { keepSplashScreen }
|
splashScreen.setKeepOnScreenCondition { keepSplashScreen }
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
// Dismiss splash screen after a short delay to ensure smooth transition
|
// Dismiss splash screen after a short delay to ensure smooth transition
|
||||||
window.decorView.postDelayed({
|
window.decorView.postDelayed({
|
||||||
keepSplashScreen = false
|
keepSplashScreen = false
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
|
||||||
// APK 安装器通道
|
// APK 安装器通道
|
||||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL)
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL)
|
||||||
.setMethodCallHandler { call, result ->
|
.setMethodCallHandler { call, result ->
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"installApk" -> {
|
"installApk" -> {
|
||||||
val apkPath = call.argument<String>("apkPath")
|
val apkPath = call.argument<String>("apkPath")
|
||||||
if (apkPath != null) {
|
if (apkPath != null) {
|
||||||
try {
|
try {
|
||||||
installApk(apkPath)
|
installApk(apkPath)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
result.error("INSTALL_FAILED", e.message, null)
|
result.error("INSTALL_FAILED", e.message, null)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.error("INVALID_PATH", "APK path is null", null)
|
result.error("INVALID_PATH", "APK path is null", null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用市场检测通道
|
// 应用市场检测通道
|
||||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, MARKET_CHANNEL)
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, MARKET_CHANNEL)
|
||||||
.setMethodCallHandler { call, result ->
|
.setMethodCallHandler { call, result ->
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"getInstallerPackageName" -> {
|
"getInstallerPackageName" -> {
|
||||||
try {
|
try {
|
||||||
val installer = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
val installer = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
packageManager.getInstallSourceInfo(packageName).installingPackageName
|
packageManager.getInstallSourceInfo(packageName).installingPackageName
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
packageManager.getInstallerPackageName(packageName)
|
packageManager.getInstallerPackageName(packageName)
|
||||||
}
|
}
|
||||||
result.success(installer)
|
result.success(installer)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
result.success(null)
|
result.success(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installApk(apkPath: String) {
|
private fun installApk(apkPath: String) {
|
||||||
val apkFile = File(apkPath)
|
val apkFile = File(apkPath)
|
||||||
if (!apkFile.exists()) {
|
if (!apkFile.exists()) {
|
||||||
throw Exception("APK file not found: $apkPath")
|
throw Exception("APK file not found: $apkPath")
|
||||||
}
|
}
|
||||||
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
|
||||||
val apkUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
val apkUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
this,
|
this,
|
||||||
"${applicationContext.packageName}.fileprovider",
|
"${applicationContext.packageName}.fileprovider",
|
||||||
apkFile
|
apkFile
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Uri.fromFile(apkFile)
|
Uri.fromFile(apkFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
|
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
|
|
||||||
// 关闭当前应用,让系统完成安装
|
// 关闭当前应用,让系统完成安装
|
||||||
finishAffinity()
|
finishAffinity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
|
||||||
/// 负责调用原生代码安装 APK 文件
|
/// 负责调用原生代码安装 APK 文件
|
||||||
class ApkInstaller {
|
class ApkInstaller {
|
||||||
static const MethodChannel _channel =
|
static const MethodChannel _channel =
|
||||||
MethodChannel('com.rwadurian.app/apk_installer');
|
MethodChannel('com.durianqueen.app/apk_installer');
|
||||||
|
|
||||||
/// 安装 APK
|
/// 安装 APK
|
||||||
static Future<bool> installApk(File apkFile) async {
|
static Future<bool> installApk(File apkFile) async {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import 'package:url_launcher/url_launcher.dart';
|
||||||
/// 检测应用安装来源,决定升级策略
|
/// 检测应用安装来源,决定升级策略
|
||||||
class AppMarketDetector {
|
class AppMarketDetector {
|
||||||
static const MethodChannel _channel =
|
static const MethodChannel _channel =
|
||||||
MethodChannel('com.rwadurian.app/app_market');
|
MethodChannel('com.durianqueen.app/app_market');
|
||||||
|
|
||||||
/// 常见应用市场包名
|
/// 常见应用市场包名
|
||||||
static const List<String> _marketPackages = [
|
static const List<String> _marketPackages = [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue