feat: 构建flutter 基座

This commit is contained in:
Booker
2026-05-18 13:36:54 +07:00
parent ce8ce5ec13
commit 37e4d73861
75 changed files with 3887 additions and 132 deletions

View File

@@ -0,0 +1,5 @@
package io.openim.flutter.im_webview_app
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View File

@@ -0,0 +1,146 @@
package io.openim.flutter.openim
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.core.content.FileProvider
import io.flutter.embedding.android.FlutterActivity
import org.conscrypt.Conscrypt
import java.security.Security
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
class MainActivity : FlutterActivity() {
private val CHANNEL = "io.openim.flutter.openim/apk_info"
private val TAG = "MainActivity"
override fun onCreate(savedInstanceState: android.os.Bundle?) {
// 华为/荣耀/OPPO 等国产设备:在任意网络请求之前同步安装 Conscrypt修复 SSL 握手失败(无 GMS 时系统 SSL 实现不完整)
try {
Security.insertProviderAt(Conscrypt.newProvider(), 1)
Log.d(TAG, "Conscrypt security provider installed (SSL fix for domestic devices)")
} catch (e: Exception) {
Log.w(TAG, "Conscrypt provider install failed: ${e.message}")
}
super.onCreate(savedInstanceState)
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
"getApkPackageName" -> {
val apkPath = call.argument<String>("apkPath")
if (apkPath != null) {
try {
val packageName = getApkPackageName(apkPath)
result.success(packageName)
} catch (e: Exception) {
result.error("ERROR", "无法解析APK包名: ${e.message}", null)
}
} else {
result.error("ERROR", "APK路径为空", null)
}
}
"getCurrentPackageName" -> {
try {
val packageName = packageName
result.success(packageName)
} catch (e: Exception) {
result.error("ERROR", "无法获取当前包名: ${e.message}", null)
}
}
"canRequestPackageInstalls" -> {
try {
val canInstall = canRequestPackageInstalls()
result.success(canInstall)
} catch (e: Exception) {
result.error("ERROR", "无法检查安装权限: ${e.message}", null)
}
}
"installApk" -> {
val apkPath = call.argument<String>("apkPath")
if (apkPath != null) {
try {
val success = installApk(apkPath)
result.success(success)
} catch (e: Exception) {
result.error("ERROR", "安装APK失败: ${e.message}", null)
}
} else {
result.error("ERROR", "APK路径为空", null)
}
}
else -> {
result.notImplemented()
}
}
}
}
private fun getApkPackageName(apkPath: String): String? {
return try {
val packageManager = packageManager
val packageInfo: PackageInfo = packageManager.getPackageArchiveInfo(
apkPath,
PackageManager.GET_ACTIVITIES
) ?: return null
packageInfo.packageName
} catch (e: Exception) {
null
}
}
/// 检查是否可以请求安装包权限Android 8.0+
private fun canRequestPackageInstalls(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Android 8.0+ 需要检查安装权限
packageManager.canRequestPackageInstalls()
} else {
// Android 8.0 以下版本默认允许安装
true
}
}
/// 使用 Intent 直接打开安装界面
private fun installApk(apkPath: String): Boolean {
return try {
val file = File(apkPath)
if (!file.exists()) {
return false
}
val intent = Intent(Intent.ACTION_VIEW).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val apkUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// Android 7.0+ 使用 FileProvider
FileProvider.getUriForFile(
this@MainActivity,
"${packageName}.fileprovider",
file
)
} else {
// Android 7.0 以下直接使用 file://
Uri.fromFile(file)
}
setDataAndType(apkUri, "application/vnd.android.package-archive")
// Android 7.0+ 需要添加临时读取权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
}
startActivity(intent)
true
} catch (e: Exception) {
false
}
}
}