From 425f5b3c58b9fece34890675e8235b025e7d338b Mon Sep 17 00:00:00 2001
From: tanlongsheng <252620078@qq.com>
Date: Sat, 15 Nov 2025 15:13:16 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0iOS=E7=94=BB=E4=B8=AD?=
=?UTF-8?q?=E7=94=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
local_plugins/native_plugin/.gitignore | 33 +++++
local_plugins/native_plugin/.metadata | 33 +++++
local_plugins/native_plugin/CHANGELOG.md | 3 +
local_plugins/native_plugin/LICENSE | 1 +
local_plugins/native_plugin/README.md | 15 +++
.../native_plugin/analysis_options.yaml | 4 +
.../native_plugin/android/.gitignore | 9 ++
.../native_plugin/android/build.gradle | 52 ++++++++
.../native_plugin/android/settings.gradle | 1 +
.../android/src/main/AndroidManifest.xml | 3 +
.../example/native_plugin/NativePlugin.java | 38 ++++++
.../native_plugin/NativePluginTest.java | 29 +++++
local_plugins/native_plugin/ios/.gitignore | 38 ++++++
.../native_plugin/ios/Assets/.gitkeep | 0
.../native_plugin/ios/Classes/FLNativeView.h | 15 +++
.../native_plugin/ios/Classes/FLNativeView.m | 83 +++++++++++++
.../native_plugin/ios/Classes/NativePlugin.h | 4 +
.../native_plugin/ios/Classes/NativePlugin.m | 114 ++++++++++++++++++
.../native_plugin/ios/Classes/PlayerView.h | 15 +++
.../native_plugin/ios/Classes/PlayerView.m | 100 +++++++++++++++
.../ios/Resources/PrivacyInfo.xcprivacy | 14 +++
.../native_plugin/ios/native_plugin.podspec | 29 +++++
.../native_plugin/lib/native_plugin.dart | 19 +++
.../lib/native_plugin_method_channel.dart | 37 ++++++
.../lib/native_plugin_platform_interface.dart | 47 ++++++++
local_plugins/native_plugin/pubspec.yaml | 72 +++++++++++
pubspec.yaml | 3 +
27 files changed, 811 insertions(+)
create mode 100644 local_plugins/native_plugin/.gitignore
create mode 100644 local_plugins/native_plugin/.metadata
create mode 100644 local_plugins/native_plugin/CHANGELOG.md
create mode 100644 local_plugins/native_plugin/LICENSE
create mode 100644 local_plugins/native_plugin/README.md
create mode 100644 local_plugins/native_plugin/analysis_options.yaml
create mode 100644 local_plugins/native_plugin/android/.gitignore
create mode 100644 local_plugins/native_plugin/android/build.gradle
create mode 100644 local_plugins/native_plugin/android/settings.gradle
create mode 100644 local_plugins/native_plugin/android/src/main/AndroidManifest.xml
create mode 100644 local_plugins/native_plugin/android/src/main/java/com/example/native_plugin/NativePlugin.java
create mode 100644 local_plugins/native_plugin/android/src/test/java/com/example/native_plugin/NativePluginTest.java
create mode 100644 local_plugins/native_plugin/ios/.gitignore
create mode 100644 local_plugins/native_plugin/ios/Assets/.gitkeep
create mode 100644 local_plugins/native_plugin/ios/Classes/FLNativeView.h
create mode 100644 local_plugins/native_plugin/ios/Classes/FLNativeView.m
create mode 100644 local_plugins/native_plugin/ios/Classes/NativePlugin.h
create mode 100644 local_plugins/native_plugin/ios/Classes/NativePlugin.m
create mode 100644 local_plugins/native_plugin/ios/Classes/PlayerView.h
create mode 100644 local_plugins/native_plugin/ios/Classes/PlayerView.m
create mode 100644 local_plugins/native_plugin/ios/Resources/PrivacyInfo.xcprivacy
create mode 100644 local_plugins/native_plugin/ios/native_plugin.podspec
create mode 100644 local_plugins/native_plugin/lib/native_plugin.dart
create mode 100644 local_plugins/native_plugin/lib/native_plugin_method_channel.dart
create mode 100644 local_plugins/native_plugin/lib/native_plugin_platform_interface.dart
create mode 100644 local_plugins/native_plugin/pubspec.yaml
diff --git a/local_plugins/native_plugin/.gitignore b/local_plugins/native_plugin/.gitignore
new file mode 100644
index 000000000..e7d347d9d
--- /dev/null
+++ b/local_plugins/native_plugin/.gitignore
@@ -0,0 +1,33 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+build/
diff --git a/local_plugins/native_plugin/.metadata b/local_plugins/native_plugin/.metadata
new file mode 100644
index 000000000..a5700b901
--- /dev/null
+++ b/local_plugins/native_plugin/.metadata
@@ -0,0 +1,33 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "35c388afb57ef061d06a39b537336c87e0e3d1b1"
+ channel: "stable"
+
+project_type: plugin
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
+ base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
+ - platform: android
+ create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
+ base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
+ - platform: ios
+ create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
+ base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/local_plugins/native_plugin/CHANGELOG.md b/local_plugins/native_plugin/CHANGELOG.md
new file mode 100644
index 000000000..41cc7d819
--- /dev/null
+++ b/local_plugins/native_plugin/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.
diff --git a/local_plugins/native_plugin/LICENSE b/local_plugins/native_plugin/LICENSE
new file mode 100644
index 000000000..ba75c69f7
--- /dev/null
+++ b/local_plugins/native_plugin/LICENSE
@@ -0,0 +1 @@
+TODO: Add your license here.
diff --git a/local_plugins/native_plugin/README.md b/local_plugins/native_plugin/README.md
new file mode 100644
index 000000000..bc8261f01
--- /dev/null
+++ b/local_plugins/native_plugin/README.md
@@ -0,0 +1,15 @@
+# native_plugin
+
+A new Flutter plugin project.
+
+## Getting Started
+
+This project is a starting point for a Flutter
+[plug-in package](https://flutter.dev/to/develop-plugins),
+a specialized package that includes platform-specific implementation code for
+Android and/or iOS.
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
+
diff --git a/local_plugins/native_plugin/analysis_options.yaml b/local_plugins/native_plugin/analysis_options.yaml
new file mode 100644
index 000000000..a5744c1cf
--- /dev/null
+++ b/local_plugins/native_plugin/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/local_plugins/native_plugin/android/.gitignore b/local_plugins/native_plugin/android/.gitignore
new file mode 100644
index 000000000..161bdcdaf
--- /dev/null
+++ b/local_plugins/native_plugin/android/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.cxx
diff --git a/local_plugins/native_plugin/android/build.gradle b/local_plugins/native_plugin/android/build.gradle
new file mode 100644
index 000000000..948c5ef6f
--- /dev/null
+++ b/local_plugins/native_plugin/android/build.gradle
@@ -0,0 +1,52 @@
+group = "com.example.native_plugin"
+version = "1.0"
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath("com.android.tools.build:gradle:8.7.0")
+ }
+}
+
+rootProject.allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+apply plugin: "com.android.library"
+
+android {
+ namespace = "com.example.native_plugin"
+
+ compileSdk = 35
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+
+ defaultConfig {
+ minSdk = 21
+ }
+
+ dependencies {
+ testImplementation("junit:junit:4.13.2")
+ testImplementation("org.mockito:mockito-core:5.0.0")
+ }
+
+ testOptions {
+ unitTests.all {
+ testLogging {
+ events "passed", "skipped", "failed", "standardOut", "standardError"
+ outputs.upToDateWhen {false}
+ showStandardStreams = true
+ }
+ }
+ }
+}
diff --git a/local_plugins/native_plugin/android/settings.gradle b/local_plugins/native_plugin/android/settings.gradle
new file mode 100644
index 000000000..9f756a98c
--- /dev/null
+++ b/local_plugins/native_plugin/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'native_plugin'
diff --git a/local_plugins/native_plugin/android/src/main/AndroidManifest.xml b/local_plugins/native_plugin/android/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..5153b5dc6
--- /dev/null
+++ b/local_plugins/native_plugin/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/local_plugins/native_plugin/android/src/main/java/com/example/native_plugin/NativePlugin.java b/local_plugins/native_plugin/android/src/main/java/com/example/native_plugin/NativePlugin.java
new file mode 100644
index 000000000..265796e9d
--- /dev/null
+++ b/local_plugins/native_plugin/android/src/main/java/com/example/native_plugin/NativePlugin.java
@@ -0,0 +1,38 @@
+package com.example.native_plugin;
+
+import androidx.annotation.NonNull;
+
+import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
+import io.flutter.plugin.common.MethodChannel.Result;
+
+/** NativePlugin */
+public class NativePlugin implements FlutterPlugin, MethodCallHandler {
+ /// The MethodChannel that will the communication between Flutter and native Android
+ ///
+ /// This local reference serves to register the plugin with the Flutter Engine and unregister it
+ /// when the Flutter Engine is detached from the Activity
+ private MethodChannel channel;
+
+ @Override
+ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
+ channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "native_plugin");
+ channel.setMethodCallHandler(this);
+ }
+
+ @Override
+ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
+ if (call.method.equals("getPlatformVersion")) {
+ result.success("Android " + android.os.Build.VERSION.RELEASE);
+ } else {
+ result.notImplemented();
+ }
+ }
+
+ @Override
+ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
+ channel.setMethodCallHandler(null);
+ }
+}
diff --git a/local_plugins/native_plugin/android/src/test/java/com/example/native_plugin/NativePluginTest.java b/local_plugins/native_plugin/android/src/test/java/com/example/native_plugin/NativePluginTest.java
new file mode 100644
index 000000000..8034030e9
--- /dev/null
+++ b/local_plugins/native_plugin/android/src/test/java/com/example/native_plugin/NativePluginTest.java
@@ -0,0 +1,29 @@
+package com.example.native_plugin;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import org.junit.Test;
+
+/**
+ * This demonstrates a simple unit test of the Java portion of this plugin's implementation.
+ *
+ * Once you have built the plugin's example app, you can run these tests from the command
+ * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
+ * you can run them directly from IDEs that support JUnit such as Android Studio.
+ */
+
+public class NativePluginTest {
+ @Test
+ public void onMethodCall_getPlatformVersion_returnsExpectedValue() {
+ NativePlugin plugin = new NativePlugin();
+
+ final MethodCall call = new MethodCall("getPlatformVersion", null);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE);
+ }
+}
diff --git a/local_plugins/native_plugin/ios/.gitignore b/local_plugins/native_plugin/ios/.gitignore
new file mode 100644
index 000000000..034771fc9
--- /dev/null
+++ b/local_plugins/native_plugin/ios/.gitignore
@@ -0,0 +1,38 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+profile
+
+DerivedData/
+build/
+GeneratedPluginRegistrant.h
+GeneratedPluginRegistrant.m
+
+.generated/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/Generated.xcconfig
+/Flutter/ephemeral/
+/Flutter/flutter_export_environment.sh
diff --git a/local_plugins/native_plugin/ios/Assets/.gitkeep b/local_plugins/native_plugin/ios/Assets/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/local_plugins/native_plugin/ios/Classes/FLNativeView.h b/local_plugins/native_plugin/ios/Classes/FLNativeView.h
new file mode 100644
index 000000000..4c49e00f4
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Classes/FLNativeView.h
@@ -0,0 +1,15 @@
+#import
+
+@interface FLNativeViewFactory : NSObject
+- (instancetype)initWithMessenger:(NSObject *)messenger;
+@end
+
+@interface FLNativeView : NSObject
+
+- (instancetype)initWithFrame:(CGRect)frame
+ viewIdentifier:(int64_t)viewId
+ arguments:(id _Nullable)args
+ binaryMessenger:(NSObject *)messenger;
+
+- (UIView *)view;
+@end
diff --git a/local_plugins/native_plugin/ios/Classes/FLNativeView.m b/local_plugins/native_plugin/ios/Classes/FLNativeView.m
new file mode 100644
index 000000000..848785a6b
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Classes/FLNativeView.m
@@ -0,0 +1,83 @@
+#import "FLNativeView.h"
+#import "PlayerView.h"
+
+@implementation FLNativeViewFactory {
+ NSObject *_messenger;
+}
+
+- (instancetype)initWithMessenger:
+ (NSObject *)messenger {
+ self = [super init];
+ if (self) {
+ _messenger = messenger;
+ }
+ return self;
+}
+
+- (NSObject *)createWithFrame:(CGRect)frame
+ viewIdentifier:(int64_t)viewId
+ arguments:(id _Nullable)args {
+ return [[FLNativeView alloc] initWithFrame:frame
+ viewIdentifier:viewId
+ arguments:args
+ binaryMessenger:_messenger];
+}
+
+/// Implementing this method is only necessary when the `arguments` in
+/// `createWithFrame` is not `nil`.
+- (NSObject *)createArgsCodec {
+ return [FlutterStandardMessageCodec sharedInstance];
+}
+
+@end
+
+@implementation FLNativeView {
+ PlayerView *_view;
+ FlutterMethodChannel *_methodChannel;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+ viewIdentifier:(int64_t)viewId
+ arguments:(id _Nullable)args
+ binaryMessenger:(NSObject *)messenger {
+ if (self = [super init]) {
+ _view = [[PlayerView alloc] init];
+ _methodChannel = [FlutterMethodChannel
+ methodChannelWithName:
+ [NSString
+ stringWithFormat:@"native_plugin/native_view_%lld", viewId]
+ binaryMessenger:messenger];
+ __weak typeof(self) weakSelf = self;
+ [_methodChannel setMethodCallHandler:^(FlutterMethodCall *_Nonnull call,
+ FlutterResult _Nonnull result) {
+ typeof(self) strongSelf = weakSelf;
+ if (strongSelf != nil) {
+ [strongSelf onMethodCall:call result:result];
+ }
+ }];
+ }
+ return self;
+}
+
+- (UIView *)view {
+ return _view;
+}
+
+- (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
+ if ([@"getInternalView" isEqualToString:call.method]) {
+ result(@((uint64_t)(_view)));
+ } else if ([@"updateContent" isEqualToString:call.method]) {
+ NSDictionary *data = call.arguments;
+ NSString *lang = data[@"lang"];
+ NSString *cn = data[@"cn"];
+ NSString *en = data[@"en"];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [_view updateWithLang:lang cn:cn en:en];
+ });
+ result(nil);
+ } else {
+ result(@(0));
+ }
+}
+
+@end
diff --git a/local_plugins/native_plugin/ios/Classes/NativePlugin.h b/local_plugins/native_plugin/ios/Classes/NativePlugin.h
new file mode 100644
index 000000000..2d0b3293e
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Classes/NativePlugin.h
@@ -0,0 +1,4 @@
+#import
+
+@interface NativePlugin : NSObject
+@end
diff --git a/local_plugins/native_plugin/ios/Classes/NativePlugin.m b/local_plugins/native_plugin/ios/Classes/NativePlugin.m
new file mode 100644
index 000000000..bee63b337
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Classes/NativePlugin.m
@@ -0,0 +1,114 @@
+#import "NativePlugin.h"
+#import "FLNativeView.h"
+#import "PlayerView.h"
+
+#import
+
+@interface NativePlugin ()
+
+@property(nonatomic, strong) NSMutableArray *_Nonnull pipContentViewArray;
+
+@end
+
+@implementation NativePlugin
+
++ (void)updateAudioSession {
+ AVAudioSession *audioSession = [AVAudioSession sharedInstance];
+ NSError *categoryError = nil;
+ if (@available(iOS 14.5, *)) {
+ [audioSession
+ setCategory:AVAudioSessionCategoryPlayback
+ mode:AVAudioSessionModeMoviePlayback
+ options:
+ AVAudioSessionCategoryOptionOverrideMutedMicrophoneInterruption
+ error:&categoryError];
+ } else {
+ // Fallback on earlier versions
+ }
+ if (categoryError) {
+ NSLog(@"Set audio session category error: %@",
+ categoryError.localizedDescription);
+ }
+ NSError *activeError = nil;
+ [audioSession setActive:YES error:&activeError];
+ if (activeError) {
+ NSLog(@"Set audio session active error: %@",
+ activeError.localizedDescription);
+ }
+}
+
++ (void)registerWithRegistrar:(NSObject *)registrar {
+ // must call this, otherwise pip will not possible
+ // https://github.com/jazzychad/PiPBugDemo
+ [NativePlugin updateAudioSession];
+
+ FlutterMethodChannel *channel =
+ [FlutterMethodChannel methodChannelWithName:@"native_plugin"
+ binaryMessenger:[registrar messenger]];
+ NativePlugin *instance = [[NativePlugin alloc] init];
+
+ FLNativeViewFactory *factory =
+ [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
+ [registrar registerViewFactory:factory withId:@"native_view"];
+
+ [registrar addMethodCallDelegate:instance channel:channel];
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ _pipContentViewArray = [NSMutableArray array];
+ }
+ return self;
+}
+
+- (void)handleMethodCall:(FlutterMethodCall *)call
+ result:(FlutterResult)result {
+ if ([@"getPlatformVersion" isEqualToString:call.method]) {
+ result([@"iOS "
+ stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
+ } else if ([@"createPipContentView" isEqualToString:call.method]) {
+ PlayerView *playerView = [[PlayerView alloc] init];
+
+ // should control the play state by event of pip, optimize it later
+ [playerView play];
+
+ [self.pipContentViewArray addObject:playerView];
+
+ result(@((uint64_t)playerView));
+ } else if ([@"disposePipContentView" isEqualToString:call.method]) {
+ uint64_t viewId = [call.arguments unsignedLongLongValue];
+ for (PlayerView *playerView in self.pipContentViewArray) {
+ if ((uint64_t)playerView == viewId) {
+ [playerView pause];
+ [self.pipContentViewArray removeObject:playerView];
+ break;
+ }
+ }
+ } else if ([@"updatePipContentView" isEqualToString:call.method]) {
+ NSDictionary *data = call.arguments;
+ NSString *lang = data[@"lang"];
+ NSString *cn = data[@"cn"];
+ NSString *en = data[@"en"];
+ NSNumber *viewIdNum = data[@"viewId"];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (viewIdNum != nil) {
+ uint64_t targetId = viewIdNum.unsignedLongLongValue;
+ for (PlayerView *playerView in self.pipContentViewArray) {
+ if ((uint64_t)playerView == targetId) {
+ [playerView updateWithLang:lang cn:cn en:en];
+ break;
+ }
+ }
+ } else {
+ PlayerView *playerView = [self.pipContentViewArray lastObject];
+ [playerView updateWithLang:lang cn:cn en:en];
+ }
+ });
+ result(nil);
+ } else {
+ result(FlutterMethodNotImplemented);
+ }
+}
+
+@end
diff --git a/local_plugins/native_plugin/ios/Classes/PlayerView.h b/local_plugins/native_plugin/ios/Classes/PlayerView.h
new file mode 100644
index 000000000..50044ae41
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Classes/PlayerView.h
@@ -0,0 +1,15 @@
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface PlayerView : UIView
+
+- (void)play;
+
+- (void)pause;
+
+- (void)updateWithLang:(NSString *)lang cn:(NSString *)cn en:(NSString *)en;
+
+@end
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/local_plugins/native_plugin/ios/Classes/PlayerView.m b/local_plugins/native_plugin/ios/Classes/PlayerView.m
new file mode 100644
index 000000000..e456fb91d
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Classes/PlayerView.m
@@ -0,0 +1,100 @@
+#import "PlayerView.h"
+
+@interface PlayerView ()
+
+@property(nonatomic, strong) UILabel *titleLabel;
+@property(nonatomic, strong) UILabel *langLabel;
+@property(nonatomic, strong) UILabel *cnLabel;
+@property(nonatomic, strong) UILabel *enLabel;
+@property(nonatomic, strong) UIStackView *stackView;
+
+@end
+
+@implementation PlayerView
+
+- (instancetype)init {
+ if (self = [super init]) {
+ self.backgroundColor = [UIColor whiteColor];
+
+ UILabel *title = [[UILabel alloc] init];
+ title.text = @"实时翻译";
+ title.font = [UIFont boldSystemFontOfSize:22];
+ title.textColor = [UIColor blackColor];
+ title.textAlignment = NSTextAlignmentCenter;
+ title.numberOfLines = 1;
+ self.titleLabel = title;
+
+ UILabel *lang = [[UILabel alloc] init];
+ lang.text = @"中文(简体) -> 英语";
+ lang.font = [UIFont systemFontOfSize:14];
+ lang.textColor = [UIColor darkGrayColor];
+ lang.textAlignment = NSTextAlignmentLeft;
+ lang.numberOfLines = 1;
+ self.langLabel = lang;
+
+ UILabel *cn = [[UILabel alloc] init];
+ cn.font = [UIFont systemFontOfSize:18];
+ cn.textColor = [UIColor blackColor];
+ cn.textAlignment = NSTextAlignmentLeft;
+ cn.numberOfLines = 0;
+ self.cnLabel = cn;
+
+ UILabel *en = [[UILabel alloc] init];
+ en.font = [UIFont systemFontOfSize:18];
+ en.textColor = [UIColor colorWithRed:0.24 green:0.54 blue:0.90 alpha:1.0];
+ en.textAlignment = NSTextAlignmentLeft;
+ en.numberOfLines = 0;
+ self.enLabel = en;
+
+ NSMutableParagraphStyle *para = [[NSMutableParagraphStyle alloc] init];
+ para.lineSpacing = 4;
+
+ self.cnLabel.attributedText = [[NSAttributedString alloc] initWithString:@"" attributes:@{NSParagraphStyleAttributeName: para}];
+
+ self.enLabel.attributedText = [[NSAttributedString alloc] initWithString:@"" attributes:@{NSParagraphStyleAttributeName: para}];
+
+ UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:@[self.titleLabel, self.langLabel, self.cnLabel, self.enLabel]];
+ stack.axis = UILayoutConstraintAxisVertical;
+ stack.spacing = 12;
+ stack.alignment = UIStackViewAlignmentFill;
+ stack.distribution = UIStackViewDistributionFill;
+ stack.translatesAutoresizingMaskIntoConstraints = NO;
+ self.stackView = stack;
+
+ self.layoutMargins = UIEdgeInsetsMake(16, 16, 16, 16);
+ [self addSubview:self.stackView];
+
+ UILayoutGuide *guide = self.layoutMarginsGuide;
+ [NSLayoutConstraint activateConstraints:@[
+ [self.stackView.topAnchor constraintEqualToAnchor:guide.topAnchor],
+ [self.stackView.leadingAnchor constraintEqualToAnchor:guide.leadingAnchor],
+ [self.stackView.trailingAnchor constraintEqualToAnchor:guide.trailingAnchor],
+ [self.stackView.bottomAnchor constraintLessThanOrEqualToAnchor:guide.bottomAnchor]
+ ]];
+ }
+ return self;
+}
+
+- (void)play {
+
+}
+
+- (void)pause {
+
+}
+
+- (void)updateWithLang:(NSString *)lang cn:(NSString *)cn en:(NSString *)en {
+ if (lang != nil) {
+ self.langLabel.text = lang;
+ }
+ NSMutableParagraphStyle *para = [[NSMutableParagraphStyle alloc] init];
+ para.lineSpacing = 4;
+ if (cn != nil) {
+ self.cnLabel.attributedText = [[NSAttributedString alloc] initWithString:cn attributes:@{NSParagraphStyleAttributeName: para}];
+ }
+ if (en != nil) {
+ self.enLabel.attributedText = [[NSAttributedString alloc] initWithString:en attributes:@{NSParagraphStyleAttributeName: para}];
+ }
+}
+
+@end
diff --git a/local_plugins/native_plugin/ios/Resources/PrivacyInfo.xcprivacy b/local_plugins/native_plugin/ios/Resources/PrivacyInfo.xcprivacy
new file mode 100644
index 000000000..a34b7e2e6
--- /dev/null
+++ b/local_plugins/native_plugin/ios/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,14 @@
+
+
+
+
+ NSPrivacyTrackingDomains
+
+ NSPrivacyAccessedAPITypes
+
+ NSPrivacyCollectedDataTypes
+
+ NSPrivacyTracking
+
+
+
diff --git a/local_plugins/native_plugin/ios/native_plugin.podspec b/local_plugins/native_plugin/ios/native_plugin.podspec
new file mode 100644
index 000000000..c84e9ffba
--- /dev/null
+++ b/local_plugins/native_plugin/ios/native_plugin.podspec
@@ -0,0 +1,29 @@
+#
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
+# Run `pod lib lint native_plugin.podspec` to validate before publishing.
+#
+Pod::Spec.new do |s|
+ s.name = 'native_plugin'
+ s.version = '0.0.1'
+ s.summary = 'A new Flutter plugin project.'
+ s.description = <<-DESC
+A new Flutter plugin project.
+ DESC
+ s.homepage = 'http://example.com'
+ s.license = { :file => '../LICENSE' }
+ s.author = { 'Your Company' => 'email@example.com' }
+ s.source = { :path => '.' }
+ s.source_files = 'Classes/**/*'
+ s.public_header_files = 'Classes/**/*.h'
+ s.dependency 'Flutter'
+ s.platform = :ios, '12.0'
+
+ # Flutter.framework does not contain a i386 slice.
+ s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
+
+ # If your plugin requires a privacy manifest, for example if it uses any
+ # required reason APIs, update the PrivacyInfo.xcprivacy file to describe your
+ # plugin's privacy impact, and then uncomment this line. For more information,
+ # see https://developer.apple.com/documentation/bundleresources/privacy_manifest_files
+ # s.resource_bundles = {'native_plugin_privacy' => ['Resources/PrivacyInfo.xcprivacy']}
+end
diff --git a/local_plugins/native_plugin/lib/native_plugin.dart b/local_plugins/native_plugin/lib/native_plugin.dart
new file mode 100644
index 000000000..c54721f1f
--- /dev/null
+++ b/local_plugins/native_plugin/lib/native_plugin.dart
@@ -0,0 +1,19 @@
+import 'native_plugin_platform_interface.dart';
+
+class NativePlugin {
+ Future getPlatformVersion() {
+ return NativePluginPlatform.instance.getPlatformVersion();
+ }
+
+ Future createPipContentView() {
+ return NativePluginPlatform.instance.createPipContentView();
+ }
+
+ Future updatePipContentView(Map data) {
+ return NativePluginPlatform.instance.updatePipContentView(data);
+ }
+
+ Future disposePipContentView(int viewId) {
+ return NativePluginPlatform.instance.disposePipContentView(viewId);
+ }
+}
diff --git a/local_plugins/native_plugin/lib/native_plugin_method_channel.dart b/local_plugins/native_plugin/lib/native_plugin_method_channel.dart
new file mode 100644
index 000000000..ec8e18ac5
--- /dev/null
+++ b/local_plugins/native_plugin/lib/native_plugin_method_channel.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+
+import 'native_plugin_platform_interface.dart';
+
+/// An implementation of [NativePluginPlatform] that uses method channels.
+class MethodChannelNativePlugin extends NativePluginPlatform {
+ /// The method channel used to interact with the native platform.
+ @visibleForTesting
+ final methodChannel = const MethodChannel('native_plugin');
+
+ @override
+ Future getPlatformVersion() async {
+ final version = await methodChannel.invokeMethod(
+ 'getPlatformVersion',
+ );
+ return version;
+ }
+
+ @override
+ Future createPipContentView() async {
+ final viewId = await methodChannel.invokeMethod(
+ 'createPipContentView',
+ );
+ return viewId ?? 0;
+ }
+
+ @override
+ Future updatePipContentView(Map data) async {
+ await methodChannel.invokeMethod('updatePipContentView', data);
+ }
+
+ @override
+ Future disposePipContentView(int viewId) async {
+ await methodChannel.invokeMethod('disposePipContentView', viewId);
+ }
+}
diff --git a/local_plugins/native_plugin/lib/native_plugin_platform_interface.dart b/local_plugins/native_plugin/lib/native_plugin_platform_interface.dart
new file mode 100644
index 000000000..c26495c2f
--- /dev/null
+++ b/local_plugins/native_plugin/lib/native_plugin_platform_interface.dart
@@ -0,0 +1,47 @@
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'native_plugin_method_channel.dart';
+
+abstract class NativePluginPlatform extends PlatformInterface {
+ /// Constructs a NativePluginPlatform.
+ NativePluginPlatform() : super(token: _token);
+
+ static final Object _token = Object();
+
+ static NativePluginPlatform _instance = MethodChannelNativePlugin();
+
+ /// The default instance of [NativePluginPlatform] to use.
+ ///
+ /// Defaults to [MethodChannelNativePlugin].
+ static NativePluginPlatform get instance => _instance;
+
+ /// Platform-specific implementations should set this with their own
+ /// platform-specific class that extends [NativePluginPlatform] when
+ /// they register themselves.
+ static set instance(NativePluginPlatform instance) {
+ PlatformInterface.verifyToken(instance, _token);
+ _instance = instance;
+ }
+
+ Future getPlatformVersion() {
+ throw UnimplementedError('platformVersion() has not been implemented.');
+ }
+
+ Future createPipContentView() {
+ throw UnimplementedError(
+ 'createPipContentView() has not been implemented.',
+ );
+ }
+
+ Future updatePipContentView(Map data) {
+ throw UnimplementedError(
+ 'updatePipContentView() has not been implemented.',
+ );
+ }
+
+ Future disposePipContentView(int viewId) {
+ throw UnimplementedError(
+ 'disposePipContentView() has not been implemented.',
+ );
+ }
+}
diff --git a/local_plugins/native_plugin/pubspec.yaml b/local_plugins/native_plugin/pubspec.yaml
new file mode 100644
index 000000000..a284bfce8
--- /dev/null
+++ b/local_plugins/native_plugin/pubspec.yaml
@@ -0,0 +1,72 @@
+name: native_plugin
+description: "A new Flutter plugin project."
+version: 0.0.1
+homepage:
+
+environment:
+ sdk: ^3.7.0
+ flutter: '>=3.3.0'
+
+dependencies:
+ flutter:
+ sdk: flutter
+ plugin_platform_interface: ^2.0.2
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ flutter_lints: ^5.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+ # This section identifies this Flutter project as a plugin project.
+ # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
+ # which should be registered in the plugin registry. This is required for
+ # using method channels.
+ # The Android 'package' specifies package in which the registered class is.
+ # This is required for using method channels on Android.
+ # The 'ffiPlugin' specifies that native code should be built and bundled.
+ # This is required for using `dart:ffi`.
+ # All these are used by the tooling to maintain consistency when
+ # adding or updating assets for this project.
+ plugin:
+ platforms:
+ android:
+ package: com.example.native_plugin
+ pluginClass: NativePlugin
+ ios:
+ pluginClass: NativePlugin
+
+ # To add assets to your plugin package, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+ #
+ # For details regarding assets in packages, see
+ # https://flutter.dev/to/asset-from-package
+ #
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/to/resolution-aware-images
+
+ # To add custom fonts to your plugin package, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts in packages, see
+ # https://flutter.dev/to/font-from-package
diff --git a/pubspec.yaml b/pubspec.yaml
index 47a634b42..d58b22f96 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -76,6 +76,7 @@ dependencies:
dio: ^5.8.0+1
sqflite: ^2.4.2
path: ^1.9.1
+ pip: ^0.0.3
connectivity_plus: ^6.1.5 # 网络连接检测依赖
speech:
path: local_plugins/speech
@@ -111,6 +112,8 @@ dependencies:
path: local_plugins/user_portrait
qq_music:
path: local_plugins/qq_music
+ native_plugin:
+ path: local_plugins/native_plugin
test:
path: local_plugins/test
in_app_purchase: ^3.2.3 # 应用内购买插件