소스 검색

feat: 增加打开包名的原生方法

lilu 1 개월 전
부모
커밋
6af7a19b1c

+ 19 - 0
android/app/src/main/kotlin/app/xixi/nomo/CoreApi.g.kt

@@ -70,6 +70,7 @@ interface CoreApi {
   fun isConnected(): Boolean?
   fun getSimInfo(): String?
   fun getChannel(): String?
+  fun openPackage(packageName: String)
 
   companion object {
     /** The codec used by CoreApi. */
@@ -250,6 +251,24 @@ interface CoreApi {
           channel.setMessageHandler(null)
         }
       }
+      run {
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.app.xixi.nomo.CoreApi.openPackage$separatedMessageChannelSuffix", codec)
+        if (api != null) {
+          channel.setMessageHandler { message, reply ->
+            val args = message as List<Any?>
+            val packageNameArg = args[0] as String
+            val wrapped: List<Any?> = try {
+              api.openPackage(packageNameArg)
+              listOf(null)
+            } catch (exception: Throwable) {
+              CoreApiPigeonUtils.wrapError(exception)
+            }
+            reply.reply(wrapped)
+          }
+        } else {
+          channel.setMessageHandler(null)
+        }
+      }
     }
   }
 }

+ 28 - 11
android/app/src/main/kotlin/app/xixi/nomo/CoreApiImpl.kt

@@ -76,12 +76,12 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
     // 事件流处理器实现
     private val eventStreamHandler = object : OnEventChangeStreamHandler() {
         override fun onListen(p0: Any?, sink: PigeonEventSink<String>) {
-            Log.d(TAG, "Flutter 开始监听事件变化")
+            VLog.d(TAG, "Flutter 开始监听事件变化")
             eventSink = sink
         }
         
         override fun onCancel(p0: Any?) {
-            Log.d(TAG, "Flutter 取消监听事件变化")
+            VLog.d(TAG, "Flutter 取消监听事件变化")
             eventSink = null
         }
     }
@@ -89,7 +89,7 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
     // 注册事件流处理器
     fun registerEventStreamHandler(messenger: BinaryMessenger) {
         OnEventChangeStreamHandler.register(messenger, eventStreamHandler)
-        Log.d(TAG, "事件流处理器已注册")
+        VLog.d(TAG, "事件流处理器已注册")
     }
 
     // 通知 Flutter VPN状态变化
@@ -131,11 +131,11 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
             try {
                 val json = Gson().toJson(message)
                 sink.success(json)
-//                Log.d(TAG, "已通知 Flutter: $json")
+//                VLog.d(TAG, "已通知 Flutter: $json")
             } catch (e: Exception) {
-                Log.e(TAG, "通知 Flutter 失败", e)
+                VLog.e(TAG, "通知 Flutter 失败", e)
             }
-        } ?: Log.w(TAG, "事件流未连接,无法通知 Flutter")
+        } ?: VLog.w(TAG, "事件流未连接,无法通知 Flutter")
     }
 
     /**
@@ -293,16 +293,16 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
             params = params,
         )
 
-        Log.i(TAG, "Starting V2Ray with permission check")
+        VLog.i(TAG, "Starting V2Ray with permission check")
         // 检查VPN权限
         val intent = VpnService.prepare(activity)
         if (intent == null) {
             // 已有VPN权限,直接启动
-            Log.i(TAG, "VPN permission already granted")
+            VLog.i(TAG, "VPN permission already granted")
             startV2RayService()
         } else {
             // 需要请求VPN权限
-            Log.i(TAG, "Requesting VPN permission")
+            VLog.i(TAG, "Requesting VPN permission")
             activity.startActivityForResult(intent, REQUEST_VPN_PERMISSION)
         }
         return true
@@ -347,6 +347,21 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
         }
     }
 
+    override fun openPackage(packageName: String) {
+        VLog.i(TAG, "openOtherApp called: $packageName")
+        try {
+            val intent = activity.packageManager.getLaunchIntentForPackage(packageName)
+            if (intent != null) {
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                activity.startActivity(intent)
+            } else {
+                VLog.w(TAG, "无法打开应用: $packageName")
+            }
+        } catch (e: Exception) {
+            VLog.e(TAG, "openOtherApp error: ${e.message}")
+        }
+    }
+
     override fun isConnected(): Boolean? {
         val isRunning = XRayApi.isServiceRunning(activity)
         VLog.i(TAG, "XRayService is running = $isRunning")
@@ -389,6 +404,8 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
         }
     }
 
+
+
     fun startV2RayService() {
         VLog.i(TAG, "============ 开始启动 V2Ray 服务 ============")
         
@@ -457,10 +474,10 @@ class CoreApiImpl(private val activity: Activity) : CoreApi {
     fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         if (requestCode == REQUEST_VPN_PERMISSION) {
             if (resultCode == Activity.RESULT_OK) {
-                Log.i(TAG, "VPN permission granted, starting V2Ray service")
+                VLog.i(TAG, "VPN permission granted, starting V2Ray service")
                 startV2RayService()
             } else {
-                Log.w(TAG, "VPN permission denied")
+                VLog.w(TAG, "VPN permission denied")
                 notifyVpnStatusChange(VPN_STATE_ERROR, ERROR_PERMISSION_DENIED, "VPN permission denied")
             }
         }

+ 16 - 0
ios/Runner/CoreApi.g.swift

@@ -100,6 +100,7 @@ protocol CoreApi {
   func isConnected() throws -> Bool?
   func getSimInfo() throws -> String?
   func getChannel() throws -> String?
+  func openPackage(packageName: String) throws
 }
 
 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -257,6 +258,21 @@ class CoreApiSetup {
     } else {
       getChannelChannel.setMessageHandler(nil)
     }
+    let openPackageChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.app.xixi.nomo.CoreApi.openPackage\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      openPackageChannel.setMessageHandler { message, reply in
+        let args = message as! [Any?]
+        let packageNameArg = args[0] as! String
+        do {
+          try api.openPackage(packageName: packageNameArg)
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
+      }
+    } else {
+      openPackageChannel.setMessageHandler(nil)
+    }
   }
 }
 

+ 3 - 0
lib/app/controllers/base_core_api.dart

@@ -78,4 +78,7 @@ abstract class BaseCoreApi {
 
   /// 获取渠道
   Future<String?> getChannel();
+
+  /// 打开应用
+  Future<void> openPackage(String packageName);
 }

+ 4 - 0
lib/app/controllers/mobile_core_api.dart

@@ -76,4 +76,8 @@ class MobileCoreApi implements BaseCoreApi {
 
   @override
   Future<String?> getChannel() => _coreApi.getChannel();
+
+  @override
+  Future<void> openPackage(String packageName) =>
+      _coreApi.openPackage(packageName);
 }

+ 5 - 0
lib/app/controllers/windows_core_api.dart

@@ -286,6 +286,11 @@ class WindowsCoreApi implements BaseCoreApi {
     return 'windows';
   }
 
+  @override
+  Future<void> openPackage(String packageName) async {
+    // TODO: 实现 Windows 打开应用
+  }
+
   /// 发送事件(供 Windows 实现内部使用)
   ///
   /// Windows 原生端可以通过 MethodChannel 发送事件:

+ 1 - 0
lib/app/modules/home/controllers/home_controller.dart

@@ -336,6 +336,7 @@ class HomeController extends BaseController {
       case BannerAction.openPkg:
         if (banner?.data != null) {
           // Open specific package
+          SystemHelper.openPackage(banner!.data!);
         }
         break;
       case BannerAction.notice:

+ 23 - 0
lib/pigeons/core_api.g.dart

@@ -281,6 +281,29 @@ class CoreApi {
       return (pigeonVar_replyList[0] as String?);
     }
   }
+
+  Future<void> openPackage(String packageName) async {
+    final String pigeonVar_channelName = 'dev.flutter.pigeon.app.xixi.nomo.CoreApi.openPackage$pigeonVar_messageChannelSuffix';
+    final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
+      pigeonVar_channelName,
+      pigeonChannelCodec,
+      binaryMessenger: pigeonVar_binaryMessenger,
+    );
+    final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[packageName]);
+    final List<Object?>? pigeonVar_replyList =
+        await pigeonVar_sendFuture as List<Object?>?;
+    if (pigeonVar_replyList == null) {
+      throw _createConnectionError(pigeonVar_channelName);
+    } else if (pigeonVar_replyList.length > 1) {
+      throw PlatformException(
+        code: pigeonVar_replyList[0]! as String,
+        message: pigeonVar_replyList[1] as String?,
+        details: pigeonVar_replyList[2],
+      );
+    } else {
+      return;
+    }
+  }
 }
 
 Stream<String> onEventChange( {String instanceName = ''}) {

+ 12 - 0
lib/utils/system_helper.dart

@@ -3,6 +3,7 @@ import 'package:url_launcher/url_launcher.dart';
 
 import '../app/components/ix_snackbar.dart';
 import '../app/constants/configs.dart';
+import '../app/controllers/base_core_api.dart';
 import '../app/data/sp/ix_sp.dart';
 import '../app/routes/app_pages.dart';
 import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as ct;
@@ -132,6 +133,17 @@ class SystemHelper {
     }
   }
 
+  static Future<void> openPackage(String packageName) async {
+    try {
+      await BaseCoreApi().openPackage(packageName);
+    } catch (e) {
+      IXSnackBar.showIXErrorSnackBar(
+        title: Strings.error.tr,
+        message: Strings.unknownError.tr,
+      );
+    }
+  }
+
   static void openPrivacyTerms() {
     final launch = IXSP.getLaunch();
     if (launch?.appConfig?.privacyAgreement != null &&

+ 1 - 0
pigeons/core_api.dart

@@ -38,6 +38,7 @@ abstract class CoreApi {
   bool? isConnected();
   String? getSimInfo();
   String? getChannel();
+  void openPackage(String packageName);
 }
 
 // 如果你需要让原生通知 Flutter 事件变化,可用 EventChannelApi