Compare commits

...

11 Commits

Author SHA1 Message Date
gem
8e7a2b0060 no message 2025-02-21 14:40:56 +08:00
gem
40409fd882 no message 2025-02-21 14:40:32 +08:00
gem
d7699c93cd no message 2025-02-07 18:05:26 +08:00
gem
e5f1398bc3 Merge commit 'f3e0de51226a3d322ae1b6ddd0d7c40b1ad1d44d' 2025-02-07 10:40:39 +08:00
gem
cacb3d6e75 no message 2025-02-07 10:39:51 +08:00
cpdl
f3e0de5122 no message 2025-02-07 10:38:54 +08:00
gem
f5ae749849 Merge commit 'c774d8c21a2c77777c74f0e93a8f35c4e25d859e' 2025-02-07 10:07:33 +08:00
cpdl
c774d8c21a no message 2025-02-07 10:06:49 +08:00
gem
c6026f57dc Merge commit '23503592f91f071d2a771c0a7fbcd3c48bef01eb' 2025-02-07 09:53:20 +08:00
cpdl
23503592f9 no message 2025-02-07 09:40:03 +08:00
cpdl
a8f3ce3307 no message 2025-01-21 11:21:35 +08:00
40 changed files with 2629 additions and 250 deletions

View File

@@ -16,10 +16,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('getPlatformVersion test', (WidgetTester tester) async { testWidgets('getPlatformVersion test', (WidgetTester tester) async {
final FlutterCocosView plugin = FlutterCocosView();
final String? version = await plugin.getPlatformVersion();
// The version string depends on the host platform running the test, so
// just assert that some non-empty string is returned.
expect(version?.isNotEmpty, true);
}); });
} }

49
example/ios/Podfile Normal file
View File

@@ -0,0 +1,49 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
platform :ios, '14.5'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
source 'https://gitea.sdws.shop/xim/open-im-sdk-repo.git' # 替换为实际的私有源 URL
source 'https://cdn.cocoapods.org/' # 默认的公共源
pod 'cocos_view_pod', '0.1.23'
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

View File

@@ -106,7 +106,6 @@
181E7CAB9BFA90CDBBC625FE /* Pods-RunnerTests.release.xcconfig */, 181E7CAB9BFA90CDBBC625FE /* Pods-RunnerTests.release.xcconfig */,
26E556676FA54FF74E61CC9C /* Pods-RunnerTests.profile.xcconfig */, 26E556676FA54FF74E61CC9C /* Pods-RunnerTests.profile.xcconfig */,
); );
name = Pods;
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -198,7 +197,7 @@
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C22789791D91DA87B0800321 /* [CP] Embed Pods Frameworks */, 129AC22480F1A498B12D0823 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -270,6 +269,23 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
129AC22480F1A498B12D0823 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -345,23 +361,6 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
C22789791D91DA87B0800321 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -457,6 +456,7 @@
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LIBTOOLFLAGS = "$(inherited)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@@ -471,12 +471,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = U4K6R29373;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
OTHER_LIBTOOLFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterCocosViewExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterCocosViewExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -587,6 +589,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LIBTOOLFLAGS = "$(inherited)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
@@ -637,6 +640,7 @@
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LIBTOOLFLAGS = "$(inherited)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
@@ -653,12 +657,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = U4K6R29373;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
OTHER_LIBTOOLFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterCocosViewExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterCocosViewExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -675,12 +682,16 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = U4K6R29373;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
ONLY_ACTIVE_ARCH = YES;
OTHER_LIBTOOLFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterCocosViewExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterCocosViewExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View File

@@ -7,7 +7,28 @@ import UIKit
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
///InitCocosIntegrationWithOptions(argc: CommandLine.argc, argv: CommandLine.unsafeArgv, launchOptions)
let flutterEngine = FlutterEngine(name: "io.flutter", project: nil)
flutterEngine.run()
let controller = FlutterViewControllerWithTransition(engine: flutterEngine, nibName: nil, bundle: nil)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
}
class FlutterViewControllerWithTransition: FlutterViewController {
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
NotificationCenter.default.post(name: NSNotification.Name("ViewWillTransition"), object: nil, userInfo: ["size": size, "coordinator": coordinator])
}
} }

View File

@@ -1,63 +1,37 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:async'; import 'package:flutter_cocos_view_example/screens/no_interaction_screen.dart';
import 'package:flutter_cocos_view_example/screens/orientation_screen.dart';
import 'package:flutter/services.dart'; import 'menu_screen.dart';
import 'package:flutter_cocos_view/flutter_cocos_view.dart'; import 'screens/api_screen.dart';
import 'screens/loader_screen.dart';
import 'screens/simple_screen.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
} }
class MyApp extends StatefulWidget { class MyApp extends StatelessWidget {
const MyApp({super.key}); const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
final _flutterCocosViewPlugin = FlutterCocosView();
@override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion =
await _flutterCocosViewPlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
// This widget is the root of your application.
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
home: Scaffold( title: 'Flutter Cocos Demo',
appBar: AppBar( theme: ThemeData(
title: const Text('Plugin example app'), primarySwatch: Colors.blue,
), visualDensity: VisualDensity.adaptivePlatformDensity,
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
), ),
initialRoute: '/',
routes: {
'/': (context) => const MenuScreen(),
'/simple': (context) => const SimpleScreen(),
'/loader': (context) => const LoaderScreen(),
'/orientation': (context) => const OrientationScreen(),
'/api': (context) => const ApiScreen(),
'/none': (context) => const NoInteractionScreen(),
},
); );
} }
} }

View File

@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
class MenuScreen extends StatefulWidget {
const MenuScreen({Key? key}) : super(key: key);
@override
State<MenuScreen> createState() => _MenuScreenState();
}
class _MenuScreenState extends State<MenuScreen> {
List<_MenuListItem> menus = [
_MenuListItem(
description: 'Simple demonstration of cocos flutter library',
route: '/simple',
title: 'Simple Cocos Demo',
),
_MenuListItem(
description: 'No interaction of cocos flutter library',
route: '/none',
title: 'No Interaction Cocos Demo',
),
_MenuListItem(
description: 'Cocos load and unload cocos demo',
route: '/loader',
title: 'Safe mode Demo',
),
_MenuListItem(
description:
'This example shows various native API exposed by the library',
route: '/api',
title: 'Native exposed API demo',
),
_MenuListItem(
title: 'Test Orientation',
route: '/orientation',
description: 'test orientation change',
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Menu List'),
),
body: Center(
child: ListView.builder(
itemCount: menus.length,
itemBuilder: (BuildContext context, int i) {
return ListTile(
title: Text(menus[i].title),
subtitle: Text(menus[i].description),
onTap: () {
Navigator.of(context).pushNamed(
menus[i].route,
);
},
);
},
),
),
);
}
}
class _MenuListItem {
final String title;
final String description;
final String route;
_MenuListItem({
required this.title,
required this.description,
required this.route,
});
}

View File

@@ -0,0 +1,168 @@
// ignore_for_file: avoid_print
import 'package:flutter/material.dart';
import "package:flutter_cocos_view/flutter_cocos_view.dart";
import 'package:pointer_interceptor/pointer_interceptor.dart';
class ApiScreen extends StatefulWidget {
const ApiScreen({Key? key}) : super(key: key);
@override
State<ApiScreen> createState() => _ApiScreenState();
}
class _ApiScreenState extends State<ApiScreen> {
CocosWidgetController? _cocosWidgetController;
double _sliderValue = 0.0;
@override
void initState() {
super.initState();
}
@override
void dispose() {
_cocosWidgetController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('API Screen'),
),
body: Card(
margin: const EdgeInsets.all(8),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: [
CocosWidget(
onCocosCreated: onCocosCreated,
onCocosMessage: onCocosMessage,
onCocosSceneLoaded: onCocosSceneLoaded,
fullscreen: false,
useAndroidViewSurface: false,
),
Positioned(
bottom: 20,
left: 20,
right: 20,
child: PointerInterceptor(
child: Card(
elevation: 10,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 20),
child: Text("Rotation speed:"),
),
Slider(
onChanged: (value) {
setState(() {
_sliderValue = value;
});
setRotationSpeed(value.toString());
},
value: _sliderValue,
min: 0,
max: 20,
),
FittedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
onPressed: () {
_cocosWidgetController?.quit();
},
child: const Text("Quit"),
),
MaterialButton(
onPressed: () {
_cocosWidgetController?.create();
},
child: const Text("Create"),
),
MaterialButton(
onPressed: () {
_cocosWidgetController?.pause();
},
child: const Text("Pause"),
),
MaterialButton(
onPressed: () {
_cocosWidgetController?.resume();
},
child: const Text("Resume"),
),
],
),
),
FittedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
onPressed: () async {
await _cocosWidgetController
?.openInNativeProcess();
},
child: const Text("Open Native"),
),
MaterialButton(
onPressed: () {
_cocosWidgetController?.unload();
},
child: const Text("Unload"),
),
MaterialButton(
onPressed: () {
_cocosWidgetController?.quit();
},
child: const Text("Silent Quit"),
),
],
),
),
],
),
),
),
),
],
),
),
);
}
void setRotationSpeed(String speed) {
_cocosWidgetController?.postMessage(
'Cube',
'SetRotationSpeed',
speed,
);
}
void onCocosMessage(message) {
print('Received message from cocos: ${message.toString()}');
}
void onCocosSceneLoaded(SceneLoaded? scene) {
if (scene != null) {
print('Received scene loaded from cocos: ${scene.name}');
print('Received scene loaded from cocos buildIndex: ${scene.buildIndex}');
} else {
print('Received scene loaded from cocos: null');
}
}
// Callback that connects the created controller to the cocos controller
void onCocosCreated(controller) {
_cocosWidgetController = controller;
}
}

View File

@@ -0,0 +1,93 @@
// ignore_for_file: avoid_print
import 'package:flutter/material.dart';
import 'package:flutter_cocos_view/flutter_cocos_view.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
class LoaderScreen extends StatefulWidget {
const LoaderScreen({Key? key}) : super(key: key);
@override
State<LoaderScreen> createState() => _LoaderScreenState();
}
class _LoaderScreenState extends State<LoaderScreen> {
CocosWidgetController? _cocosWidgetController;
double _sliderValue = 0.0;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Safe Mode Screen'),
),
body: Card(
margin: const EdgeInsets.all(8),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: <Widget>[
CocosWidget(
onCocosCreated: onCocosCreated,
onCocosMessage: onCocosMessage,
useAndroidViewSurface: true,
),
Positioned(
bottom: 20,
left: 20,
right: 20,
child: PointerInterceptor(
child: Card(
elevation: 10,
child: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 20),
child: Text("Rotation speed:"),
),
Slider(
onChanged: (value) {
setState(() {
_sliderValue = value;
});
setRotationSpeed(value.toString());
},
value: _sliderValue,
min: 0,
max: 20,
),
],
),
),
),
),
],
),
),
);
}
void setRotationSpeed(String speed) {
_cocosWidgetController?.postMessage(
'Cube',
'SetRotationSpeed',
speed,
);
}
void onCocosMessage(message) {
print('Received message from cocos: ${message.toString()}');
}
// Callback that connects the created controller to the cocos controller
void onCocosCreated(controller) {
_cocosWidgetController = controller;
}
}

View File

@@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:flutter_cocos_view/flutter_cocos_view.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
class NoInteractionScreen extends StatefulWidget {
const NoInteractionScreen({Key? key}) : super(key: key);
@override
State<NoInteractionScreen> createState() => _NoInteractionScreenState();
}
class _NoInteractionScreenState extends State<NoInteractionScreen> {
static final GlobalKey<ScaffoldState> _scaffoldKey =
GlobalKey<ScaffoldState>();
CocosWidgetController? _cocosWidgetController;
@override
void initState() {
super.initState();
}
@override
void dispose() {
_cocosWidgetController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('No Interaction Screen'),
),
body: Card(
margin: const EdgeInsets.all(8),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: [
CocosWidget(
onCocosCreated: _onCocosCreated,
onCocosMessage: onCocosMessage,
onCocosSceneLoaded: onCocosSceneLoaded,
useAndroidViewSurface: true,
borderRadius: const BorderRadius.all(Radius.circular(70)),
),
Positioned(
bottom: 20,
left: 20,
right: 20,
child: PointerInterceptor(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed('/simple');
},
child: const Text('Switch Flutter Screen'),
),
),
),
],
),
),
);
}
void setRotationSpeed(String speed) {
_cocosWidgetController?.postMessage(
'Cube',
'SetRotationSpeed',
speed,
);
}
void onCocosMessage(message) {
print('Received message from cocos: ${message.toString()}');
}
void onCocosSceneLoaded(SceneLoaded? scene) {
if (scene != null) {
print('Received scene loaded from cocos: ${scene.name}');
print('Received scene loaded from cocos buildIndex: ${scene.buildIndex}');
} else {
print('Received scene loaded from cocos: null');
}
}
// Callback that connects the created controller to the cocos controller
void _onCocosCreated(controller) {
controller.resume();
_cocosWidgetController = controller;
}
}

View File

@@ -0,0 +1,108 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cocos_view/flutter_cocos_view.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
class OrientationScreen extends StatefulWidget {
const OrientationScreen({Key? key}) : super(key: key);
@override
State<OrientationScreen> createState() => _OrientationScreenState();
}
class _OrientationScreenState extends State<OrientationScreen> {
CocosWidgetController? _cocosWidgetController;
double _sliderValue = 0.0;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Orientation Screen'),
),
body: Card(
margin: const EdgeInsets.all(8),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: <Widget>[
CocosWidget(
onCocosCreated: onCocosCreated,
onCocosMessage: onCocosMessage,
useAndroidViewSurface: true,
),
Positioned(
bottom: 20,
left: 20,
right: 20,
child: PointerInterceptor(
child: Card(
elevation: 10,
child: Column(
children: <Widget>[
ElevatedButton(
onPressed: () {
if (MediaQuery.of(context).orientation ==
Orientation.portrait) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight
]);
} else if (MediaQuery.of(context).orientation ==
Orientation.landscape) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp]);
}
},
child: const Text("Change Orientation"),
),
const Padding(
padding: EdgeInsets.only(top: 20),
child: Text("Rotation speed:"),
),
Slider(
onChanged: (value) {
setState(() {
_sliderValue = value;
});
setRotationSpeed(value.toString());
},
value: _sliderValue,
min: 0,
max: 20,
),
],
),
),
),
),
],
),
),
);
}
void setRotationSpeed(String speed) {
_cocosWidgetController?.postMessage(
'Cube',
'SetRotationSpeed',
speed,
);
}
void onCocosMessage(message) {
print('Received message from cocos: ${message.toString()}');
}
// Callback that connects the created controller to the cocos controller
void onCocosCreated(controller) {
_cocosWidgetController = controller;
}
}

View File

@@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:flutter_cocos_view/flutter_cocos_view.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
class SimpleScreen extends StatefulWidget {
const SimpleScreen({Key? key}) : super(key: key);
@override
State<SimpleScreen> createState() => _SimpleScreenState();
}
class _SimpleScreenState extends State<SimpleScreen> {
static final GlobalKey<ScaffoldState> _scaffoldKey =
GlobalKey<ScaffoldState>();
CocosWidgetController? _cocosWidgetController;
double _sliderValue = 0.0;
@override
void initState() {
super.initState();
}
@override
void dispose() {
_cocosWidgetController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('Simple Screen'),
),
body: Card(
margin: const EdgeInsets.all(0),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: [
CocosWidget(
onCocosCreated: _onCocosCreated,
onCocosMessage: onCocosMessage,
onCocosSceneLoaded: onCocosSceneLoaded,
useAndroidViewSurface: false,
borderRadius: const BorderRadius.all(Radius.circular(70)),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: PointerInterceptor(
child: Card(
elevation: 10,
child: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 20),
child: Text("Rotation speed:"),
),
Slider(
onChanged: (value) {
setState(() {
_sliderValue = value;
});
setRotationSpeed(value.toString());
},
value: _sliderValue,
min: 0.0,
max: 1.0,
),
],
),
),
),
),
],
)),
);
}
void setRotationSpeed(String speed) {
_cocosWidgetController?.postMessage(
'Cube',
'SetRotationSpeed',
speed,
);
}
void onCocosMessage(message) {
print('Received message from cocos: ${message.toString()}');
}
void onCocosSceneLoaded(SceneLoaded? scene) {
if (scene != null) {
print('Received scene loaded from cocos: ${scene.name}');
print('Received scene loaded from cocos buildIndex: ${scene.buildIndex}');
} else {
print('Received scene loaded from cocos: null');
}
}
// Callback that connects the created controller to the cocos controller
void _onCocosCreated(controller) {
print('Received _onCocosCreated: null');
controller.resume();
_cocosWidgetController = controller;
}
}

View File

@@ -57,14 +57,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -77,11 +69,6 @@ packages:
relative: true relative: true
source: path source: path
version: "0.0.1" version: "0.0.1"
flutter_driver:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -95,16 +82,6 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
integration_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@@ -169,14 +146,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.9.0"
platform:
dependency: transitive
description:
name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -185,14 +154,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
process: pointer_interceptor:
dependency: transitive dependency: "direct main"
description: description:
name: process name: pointer_interceptor
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" sha256: adf7a637f97c077041d36801b43be08559fd4322d2127b3f20bb7be1b9eebc22
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.2" version: "0.9.3+7"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -222,6 +191,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.1"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
@@ -230,14 +207,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
sync_http:
dependency: transitive
description:
name: sync_http
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@@ -270,14 +239,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.5" version: "14.2.5"
webdriver:
dependency: transitive
description:
name: webdriver
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
sdks: sdks:
dart: ">=3.5.4 <4.0.0" dart: ">=3.4.4 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54" flutter: ">=3.18.0-18.0.pre.54"

View File

@@ -5,7 +5,7 @@ description: "Demonstrates how to use the flutter_cocos_view plugin."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment: environment:
sdk: ^3.5.4 sdk: ^3.4.4
# Dependencies specify other packages that your package needs in order to work. # Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions # To automatically upgrade your package dependencies to the latest versions
@@ -28,10 +28,8 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8 cupertino_icons: ^1.0.8
pointer_interceptor: ^0.9.3+2
dev_dependencies: dev_dependencies:
integration_test:
sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter

View File

@@ -0,0 +1,330 @@
//
// CocosPlayerUtils.swift
// flutter_cocos_widget
//
// Created by Rex Raphael on 30/01/2021.
//
import Foundation
private var cocos_warmed_up = false
// Hack to work around iOS SDK 4.3 linker problem
// we need at least one __TEXT, __const section entry in main application .o files
// to get this section emitted at right time and so avoid LC_ENCRYPTION_INFO size miscalculation
private let constsection = 0
// keep arg for cocos init from non main
var gArgc: Int32 = 0
var gArgv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>? = nil
var appLaunchOpts: [UIApplication.LaunchOptionsKey: Any]? = [:]
/***********************************PLUGIN_ENTRY STARTS**************************************/
public func InitCocosIntegration(argc: Int32, argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?) {
gArgc = argc
gArgv = argv
}
public func InitCocosIntegrationWithOptions(
argc: Int32,
argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?,
_ launchingOptions: [UIApplication.LaunchOptionsKey: Any]?) {
gArgc = argc
gArgv = argv
appLaunchOpts = launchingOptions
}
/***********************************PLUGIN_ENTRY END**************************************/
// Load cocos framework for fisrt run
func CocosFrameworkLoad() -> dcocos_bridge? {
return dcocos_bridge.instance()
}
/*********************************** GLOBAL FUNCS & VARS START**************************************/
public var globalControllers: Array<FLTCocosWidgetController> = [FLTCocosWidgetController]()
private var cocosPlayerUtils: CocosPlayerUtils? = nil
func GetCocosPlayerUtils() -> CocosPlayerUtils {
if cocosPlayerUtils == nil {
cocosPlayerUtils = CocosPlayerUtils()
}
return cocosPlayerUtils ?? CocosPlayerUtils()
}
/*********************************** GLOBAL FUNCS & VARS END****************************************/
//var controller: CocosAppController?
var sharedApplication: UIApplication?
@objc protocol CocosEventListener: AnyObject {
func onReceiveMessage(_ message: UnsafePointer<Int8>?)
}
@objc public class CocosPlayerUtils: UIResponder, UIApplicationDelegate {
var ufw: dcocos_bridge!
private var _isCocosPaused = false
private var _isCocosReady = false
private var _isCocosLoaded = false
override init() {
super.init()
//
NotificationCenter.default.addObserver(self, selector: #selector(handleViewWillTransition), name: NSNotification.Name("ViewWillTransition"), object: nil)
}
deinit {
//
NotificationCenter.default.removeObserver(self)
}
@objc func handleViewWillTransition(notification: Notification) {
guard let size = notification.userInfo?["size"] as? CGSize,
let coordinator = notification.userInfo?["coordinator"] as? UIViewControllerTransitionCoordinator else {
return
}
//
print("CocosPlayerUtils will transition to size: \(size)")
//
let selector = NSSelectorFromString("viewWillTransitionToSize:withTransitionCoordinator:")
if self.ufw.responds(to: selector) {
self.ufw.perform(selector, with: size, with: coordinator)
}
}
func initCocos() {
if (self.cocosIsInitiallized()) {
//todo
//self.ufw?.showCocosWindow()
return
}
//
//UIDevice.current.beginGeneratingDeviceOrientationNotifications()
self.ufw = CocosFrameworkLoad()
// PodBundle
let bundle = Bundle(for: dcocos_bridge.self)
// `YourPodResources.bundle`
if let bundleURL = bundle.url(forResource: "cocos_main_bundle", withExtension: "bundle") {
let bundlePath = bundleURL.path
print("Bundle absolute path: \(bundlePath)")
self.ufw.configureCocos2dSearchPaths(bundlePath)
} else {
print("Could not find the bundle.")
}
//self.ufw?.setDataBundleId("com.cocos3d.framework")
self.ufw.initPlatform()
let application = UIApplication.shared
self.ufw.application(application, didFinishLaunchingWithOptions: appLaunchOpts )
registerCocosListener()
// self.ufw?.runEmbedded(withArgc: gArgc, argv: gArgv, appLaunchOpts: appLaunchOpts)
// if self.ufw?.appController() != nil {
// controller = self.ufw?.appController()
// controller?.cocosMessageHandler = self.cocosMessageHandlers
// controller?.cocosSceneLoadedHandler = self.cocosSceneLoadedHandlers
// self.ufw?.appController()?.window?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue - 1)
// }
_isCocosLoaded = true
}
// check if cocos is initiallized
func cocosIsInitiallized() -> Bool {
if self.ufw != nil {
return true
}
return false
}
// Create new cocos player
func createPlayer(completed: @escaping (_ view: UIView?) -> Void) {
if self.cocosIsInitiallized() && self._isCocosReady {
//todo
//completed(controller?.rootView)
completed(nil)
return
}
NotificationCenter.default.addObserver(forName: NSNotification.Name("CocosReady"), object: nil, queue: OperationQueue.main, using: { note in
self._isCocosReady = true
//todo
//completed(controller?.rootView)
completed(nil)
})
DispatchQueue.main.async {
// if (sharedApplication == nil) {
// sharedApplication = UIApplication.shared
// }
// Always keep Flutter window on top
// let flutterUIWindow = sharedApplication?.keyWindow
// flutterUIWindow?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue + 1) // Always keep Flutter window in top
// sharedApplication?.keyWindow?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue + 1)
self.initCocos()
cocos_warmed_up = true
self._isCocosReady = true
self._isCocosLoaded = true
self.listenAppState()
//todo
//completed(controller?.rootView)
completed(nil)
}
}
func registerCocosListener() {
if self.cocosIsInitiallized() {
// self.ufw?.register(self)
}
}
func unregisterCocosListener() {
if self.cocosIsInitiallized() {
// self.ufw?.unregisterFrameworkListener(self)
}
}
@objc
public func cocosDidUnload(_ notification: Notification!) {
unregisterCocosListener()
self.ufw = nil
self._isCocosReady = false
self._isCocosLoaded = false
}
@objc func handleAppStateDidChange(notification: Notification?) {
if !self._isCocosReady {
return
}
//todo
//let cocosAppController = self.ufw?.appController() as? CocosAppController
// let cocosAppController = nil
let application = UIApplication.shared
if notification?.name == UIApplication.willResignActiveNotification {
self.ufw?.applicationWillResignActive(application)
} else if notification?.name == UIApplication.didEnterBackgroundNotification {
// self.ufw?.applicationDidEnterBackground(application)
} else if notification?.name == UIApplication.willEnterForegroundNotification {
// self.ufw?.applicationWillEnterForeground(application)
} else if notification?.name == UIApplication.didBecomeActiveNotification {
self.ufw?.applicationDidBecomeActive(application)
} else if notification?.name == UIApplication.willTerminateNotification {
self.ufw?.applicationWillTerminate(application)
} else if notification?.name == UIApplication.didReceiveMemoryWarningNotification {
// self.ufw?.applicationDidReceiveMemoryWarning(application)
}
}
// Listener for app lifecycle eventa
func listenAppState() {
for name in [
UIApplication.didBecomeActiveNotification,
UIApplication.didEnterBackgroundNotification,
UIApplication.willTerminateNotification,
UIApplication.willResignActiveNotification,
UIApplication.willEnterForegroundNotification,
UIApplication.didReceiveMemoryWarningNotification
] {
NotificationCenter.default.addObserver(
self,
selector: #selector(self.handleAppStateDidChange),
name: name,
object: nil)
}
}
// Pause cocos player
func pause() {
//todo
// self.ufw?.pause(true)
self._isCocosPaused = true
}
// Resume cocos player
func resume() {
//todo
//self.ufw?.pause(false)
self._isCocosPaused = false
}
// Unoad cocos player
func unload() {
//todo
//self.ufw?.unloadApplication()
}
func isCocosLoaded() -> Bool {
return _isCocosLoaded
}
func isCocosPaused() -> Bool {
return _isCocosPaused
}
// Quit cocos player application
func quit() {
//todo
//self.ufw?.quitApplication(0)
self._isCocosLoaded = false
}
// Post message to cocos
func postMessageToCocos(gameObject: String?, cocosMethodName: String?, cocosMessage: String?) {
if self.cocosIsInitiallized() {
//todo
//self.ufw?.sendMessageToGO(withName: gameObject, functionName: cocosMethodName, message: cocosMessage)
}
}
/// Handle incoming cocos messages looping through all controllers and passing payload to
/// the controller handler methods
@objc
func cocosMessageHandlers(_ message: UnsafePointer<Int8>?) {
for c in globalControllers {
if let strMsg = message {
c.handleMessage(message: String(utf8String: strMsg) ?? "")
} else {
c.handleMessage(message: "")
}
}
}
func cocosSceneLoadedHandlers(name: UnsafePointer<Int8>?, buildIndex: UnsafePointer<Int32>?, isLoaded: UnsafePointer<Bool>?, isValid: UnsafePointer<Bool>?) {
if let sceneName = name,
let bIndex = buildIndex,
let loaded = isLoaded,
let valid = isValid {
let loadedVal = Bool((Int(bitPattern: loaded) != 0))
let validVal = Bool((Int(bitPattern: valid) != 0))
let addObject: Dictionary<String, Any> = [
"name": String(utf8String: sceneName) ?? "",
"buildIndex": Int(bitPattern: bIndex),
"isLoaded": loadedVal,
"isValid": validVal,
]
for c in globalControllers {
c.handleSceneChangeEvent(info: addObject)
}
}
}
}

View File

@@ -0,0 +1,13 @@
//
// FLTCocosOptionsSink.swift
// flutter_unity_widget
//
// Created by Rex Raphael on 30/01/2021.
//
import Foundation
// Defines map UI options writable from Flutter.
protocol FLTCocosOptionsSink: AnyObject {
func setDisabledUnload(enabled: Bool)
}

View File

@@ -0,0 +1,20 @@
//
// FLTCocosView.swift
// flutter_unity_widget
//
// Created by Rex Raphael on 30/01/2021.
//
import Foundation
import UIKit
class FLTCocosView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
if (!self.bounds.isEmpty) {
//todo
GetCocosPlayerUtils().ufw?.getCocosView()?.frame = self.bounds
}
}
}

View File

@@ -0,0 +1,30 @@
//
// FLTCocosViewFactory.swift
// flutter_unity_widget
//
// Created by Rex Raphael on 30/01/2021.
//
import Foundation
class FLTCocosWidgetFactory: NSObject, FlutterPlatformViewFactory {
private weak var registrar: FlutterPluginRegistrar?
init(registrar: NSObjectProtocol & FlutterPluginRegistrar) {
super.init()
self.registrar = registrar
}
func createArgsCodec() -> (NSObjectProtocol & FlutterMessageCodec) {
return FlutterStandardMessageCodec.sharedInstance()
}
func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
let controller = FLTCocosWidgetController(
frame: frame,
viewIdentifier: viewId,
arguments: args,
registrar: registrar!)
return controller
}
}

View File

@@ -0,0 +1,188 @@
//
// FLTCocosViewController.swift
// flutter_cocos_widget
//
// Created by Rex Raphael on 30/01/2021.
//
import Foundation
// Defines cocos controllable from Flutter.
public class FLTCocosWidgetController: NSObject, FLTCocosOptionsSink, FlutterPlatformView {
private var _rootView: FLTCocosView
private var viewId: Int64 = 0
private var channel: FlutterMethodChannel?
private weak var registrar: (NSObjectProtocol & FlutterPluginRegistrar)?
private var _disposed = false
init(
frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?,
registrar: NSObjectProtocol & FlutterPluginRegistrar
) {
//CGRect(x: 0, y: 0, width: 700, height: 700)
self._rootView = FLTCocosView(frame: frame)
super.init()
globalControllers.append(self)
self.viewId = viewId
let channelName = String(format: "plugin.gem.com/cocos_view_%lld", viewId)
self.channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())
self.channel?.setMethodCallHandler(self.methodHandler)
self.attachView()
}
func methodHandler(_ call: FlutterMethodCall, result: FlutterResult) {
NSLog("call : \(call.method)")
if call.method == "cocos#dispose" {
self.dispose()
result(nil)
} else {
self.reattachView()
if call.method == "cocos#isReady" {
result(GetCocosPlayerUtils().cocosIsInitiallized())
} else if call.method == "cocos#isLoaded" {
let _isUnloaded = GetCocosPlayerUtils().isCocosLoaded()
result(_isUnloaded)
} else if call.method == "cocos#createCocosPlayer" {
startCocosIfNeeded()
result(nil)
} else if call.method == "cocos#isPaused" {
let _isPaused = GetCocosPlayerUtils().isCocosPaused()
result(_isPaused)
} else if call.method == "cocos#pausePlayer" {
GetCocosPlayerUtils().pause()
result(nil)
} else if call.method == "cocos#postMessage" {
self.postMessage(call: call, result: result)
result(nil)
} else if call.method == "cocos#resumePlayer" {
GetCocosPlayerUtils().resume()
result(nil)
} else if call.method == "cocos#unloadPlayer" {
GetCocosPlayerUtils().unload()
result(nil)
} else if call.method == "cocos#quitPlayer" {
GetCocosPlayerUtils().quit()
result(nil)
} else if call.method == "cocos#waitForCocos" {
result(nil)
} else {
result(FlutterMethodNotImplemented)
}
}
}
func setDisabledUnload(enabled: Bool) {
}
public func view() -> UIView {
return _rootView;
}
private func startCocosIfNeeded() {
GetCocosPlayerUtils().createPlayer(completed: { [self] (view: UIView?) in
})
}
func attachView() {
startCocosIfNeeded()
//GetCocosPlayerUtils().ufw?.setCocosView(_rootView)
// self.channel?.invokeMethod("events#onViewReattached", arguments: "")
let cocosView = GetCocosPlayerUtils().ufw?.getCocosView()
if let superview = cocosView?.superview {
cocosView?.removeFromSuperview()
superview.layoutIfNeeded()
}
if let cocosView = cocosView {
_rootView.addSubview(cocosView)
_rootView.layoutIfNeeded()
self.channel?.invokeMethod("events#onViewReattached", arguments: "")
}
GetCocosPlayerUtils().resume()
}
func reattachView() {
//todo
let cocosView = GetCocosPlayerUtils().ufw?.getCocosView()
let superview = cocosView?.superview
if superview != _rootView {
attachView()
}
GetCocosPlayerUtils().resume()
}
func removeViewIfNeeded() {
if GetCocosPlayerUtils().ufw == nil {
return
}
let cocosView = GetCocosPlayerUtils().ufw?.getCocosView()
if _rootView == cocosView?.superview {
if globalControllers.isEmpty {
cocosView?.removeFromSuperview()
cocosView?.superview?.layoutIfNeeded()
} else {
globalControllers.last?.reattachView()
}
}
GetCocosPlayerUtils().resume()
}
func dispose() {
if _disposed {
return
}
globalControllers.removeAll{ value in
return value == self
}
channel?.setMethodCallHandler(nil)
removeViewIfNeeded()
_disposed = true
}
/// Handles messages from cocos in the current view
func handleMessage(message: String) {
self.channel?.invokeMethod("events#onCocosMessage", arguments: message)
}
/// Handles scene changed event from cocos in the current view
func handleSceneChangeEvent(info: Dictionary<String, Any>) {
self.channel?.invokeMethod("events#onCocosSceneLoaded", arguments: info)
}
/// Post messages to cocos from flutter
func postMessage(call: FlutterMethodCall, result: FlutterResult) {
guard let args = call.arguments else {
result("iOS could not recognize flutter arguments in method: (postMessage)")
return
}
if let myArgs = args as? [String: Any],
let gObj = myArgs["gameObject"] as? String,
let method = myArgs["methodName"] as? String,
let message = myArgs["message"] as? String {
GetCocosPlayerUtils().postMessageToCocos(gameObject: gObj, cocosMethodName: method, cocosMessage: message)
result(nil)
} else {
result(FlutterError(code: "-1", message: "iOS could not extract " +
"flutter arguments in method: (postMessage)", details: nil))
}
}
}

View File

@@ -1,11 +1,14 @@
import Flutter import Flutter
import UIKit import UIKit
public class FlutterCocosViewPlugin: NSObject, FlutterPlugin { public class SwiftFlutterCocosViewPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) { public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_cocos_view", binaryMessenger: registrar.messenger()) print("FlutterCocosViewPlugin registered~~~~~~~~~~~~~~") //
let instance = FlutterCocosViewPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
let fuwFactory = FLTCocosWidgetFactory(registrar: registrar)
registrar.register(fuwFactory, withId: "plugin.gem.com/cocos_view", gestureRecognizersBlockingPolicy: FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
@@ -17,3 +20,4 @@ public class FlutterCocosViewPlugin: NSObject, FlutterPlugin {
} }
} }
} }

View File

@@ -0,0 +1,13 @@
//
// FlutterCocosWidgetPlugin.h
// FlutterCocosWidgetPlugin
//
// Created by Kris Pypen on 8/1/19.
// Updated by Rex Raphael on 8/27/2020.
//
#import <Flutter/Flutter.h>
@interface FlutterCocosWidgetPlugin : NSObject<FlutterPlugin>
@end

View File

@@ -0,0 +1,22 @@
#import "FlutterCocosWidgetPlugin.h"
#import <Foundation/Foundation.h>
#if __has_include(<flutter_cocos_view/flutter_cocos_-Swift.h>)
#import <flutter_cocos_view/flutter_cocos_view-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import <flutter_cocos_view/flutter_cocos_view-Swift.h>
#endif
@implementation FlutterCocosWidgetPlugin {
NSObject<FlutterPluginRegistrar>* _registrar;
FlutterMethodChannel* _channel;
NSMutableDictionary* _cocosControllers;
}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftFlutterCocosViewPlugin registerWithRegistrar:registrar];
}
@end

View File

@@ -0,0 +1,8 @@
#ifndef your_plugin_Bridging_Header_h
#define your_plugin_Bridging_Header_h
#import <cocos_view_pod/dcocos_bridge.h>
#endif /* your_plugin_Bridging_Header_h */

View File

@@ -15,10 +15,17 @@ A new Flutter plugin project.
s.source = { :path => '.' } s.source = { :path => '.' }
s.source_files = 'Classes/**/*' s.source_files = 'Classes/**/*'
s.dependency 'Flutter' s.dependency 'Flutter'
s.platform = :ios, '12.0' s.dependency 'cocos_view_pod','0.1.23'
s.platform = :ios, '14.5'
#s.public_header_files = 'Classes/**/*.h'
#s.vendored_libraries = 'Libs/**/*.a'
#s.libraries = 'dcocos'
#s.private_header_files = 'Classes/flutter_cocos_view-Bridging-Header.h'
s.static_framework = true
# Flutter.framework does not contain a i386 slice. # Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES'}
s.user_target_xcconfig = { 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES' }
s.swift_version = '5.0' s.swift_version = '5.0'
# If your plugin requires a privacy manifest, for example if it uses any # If your plugin requires a privacy manifest, for example if it uses any

View File

@@ -5,10 +5,11 @@
// platforms in the `pubspec.yaml` at // platforms in the `pubspec.yaml` at
// https://flutter.dev/to/pubspec-plugin-platforms. // https://flutter.dev/to/pubspec-plugin-platforms.
import 'flutter_cocos_view_platform_interface.dart'; library flutter_cocos_view;
class FlutterCocosView { export 'src/facade_controller.dart';
Future<String?> getPlatformVersion() { export 'src/facade_widget.dart'
return FlutterCocosViewPlatform.instance.getPlatformVersion(); if (dart.library.io) 'src/io/cocos_widget.dart';
} export 'src/helpers/events.dart';
} export 'src/helpers/misc.dart';
export 'src/helpers/types.dart';

View File

@@ -1,17 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'flutter_cocos_view_platform_interface.dart';
/// An implementation of [FlutterCocosViewPlatform] that uses method channels.
class MethodChannelFlutterCocosView extends FlutterCocosViewPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('flutter_cocos_view');
@override
Future<String?> getPlatformVersion() async {
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
}

View File

@@ -1,29 +0,0 @@
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'flutter_cocos_view_method_channel.dart';
abstract class FlutterCocosViewPlatform extends PlatformInterface {
/// Constructs a FlutterCocosViewPlatform.
FlutterCocosViewPlatform() : super(token: _token);
static final Object _token = Object();
static FlutterCocosViewPlatform _instance = MethodChannelFlutterCocosView();
/// The default instance of [FlutterCocosViewPlatform] to use.
///
/// Defaults to [MethodChannelFlutterCocosView].
static FlutterCocosViewPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [FlutterCocosViewPlatform] when
/// they register themselves.
static set instance(FlutterCocosViewPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
}

View File

@@ -0,0 +1,103 @@
typedef void CocosCreatedCallback(CocosWidgetController controller);
abstract class CocosWidgetController {
static dynamic webRegistrar;
/// Method required for web initialization
static void registerWith(dynamic registrar) {
webRegistrar = registrar;
}
/// Initialize [CocosWidgetController] with [id]
/// Mainly for internal use when instantiating a [CocosWidgetController] passed
/// in [CocosWidget.onCocosCreated] callback.
static Future<CocosWidgetController> init(
int id, dynamic cocosWidgetState) async {
throw UnimplementedError('init() has not been implemented.');
}
/// Checks to see if Cocos player is ready to be used
/// Returns `true` if Cocos player is ready.
Future<bool?>? isReady() {
throw UnimplementedError('isReady() has not been implemented.');
}
/// Get the current pause state of the Cocos player
/// Returns `true` if Cocos player is paused.
Future<bool?>? isPaused() {
throw UnimplementedError('isPaused() has not been implemented.');
}
/// Get the current load state of the Cocos player
/// Returns `true` if Cocos player is loaded.
Future<bool?>? isLoaded() {
throw UnimplementedError('isLoaded() has not been implemented.');
}
/// Helper method to know if Cocos has been put in background mode (WIP) unstable
/// Returns `true` if Cocos player is in background.
Future<bool?>? inBackground() {
throw UnimplementedError('inBackground() has not been implemented.');
}
/// Creates a Cocos player if it's not already created. Please only call this if Cocos is not ready,
/// or is in unloaded state. Use [isLoaded] to check.
/// Returns `true` if Cocos player was created succesfully.
Future<bool?>? create() {
throw UnimplementedError('create() has not been implemented.');
}
/// Post message to Cocos from flutter. This method takes in a string [message].
/// The [gameObject] must match the name of an actual Cocos game object in a scene at runtime, and the [methodName],
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method
///
/// ```dart
/// postMessage("GameManager", "openScene", "ThirdScene")
/// ```
Future<void>? postMessage(String gameObject, methodName, message) {
throw UnimplementedError('postMessage() has not been implemented.');
}
/// Post message to Cocos from flutter. This method takes in a Json or map structure as the [message].
/// The [gameObject] must match the name of an actual Cocos game object in a scene at runtime, and the [methodName],
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method
///
/// ```dart
/// postJsonMessage("GameManager", "openScene", {"buildIndex": 3, "name": "ThirdScene"})
/// ```
Future<void>? postJsonMessage(
String gameObject, String methodName, Map<String, dynamic> message) {
throw UnimplementedError('postJsonMessage() has not been implemented.');
}
/// Pause the Cocos in-game player with this method
Future<void>? pause() {
throw UnimplementedError('pause() has not been implemented.');
}
/// Resume the Cocos in-game player with this method idf it is in a paused state
Future<void>? resume() {
throw UnimplementedError('resume() has not been implemented.');
}
/// Sometimes you want to open Cocos in it's own process and openInNativeProcess does just that.
/// It works for Android and iOS is WIP
Future<void>? openInNativeProcess() {
throw UnimplementedError('openInNativeProcess() has not been implemented.');
}
/// Unloads Cocos player from th current process (Works on Android only for now)
/// iOS is WIP. For more information please read [Cocos Docs](https://docs.Cocos3d.com/2020.2/Documentation/Manual/CocosasaLibrary.html)
Future<void>? unload() {
throw UnimplementedError('unload() has not been implemented.');
}
/// Quits Cocos player. Note that this kills the current flutter process, thus quiting the app
Future<void>? quit() {
throw UnimplementedError('quit() has not been implemented.');
}
void dispose() {
throw UnimplementedError('dispose() has not been implemented.');
}
}

View File

@@ -0,0 +1,89 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter_cocos_view/src/facade_controller.dart';
import 'helpers/misc.dart';
class CocosWidget extends StatefulWidget {
CocosWidget({
Key? key,
required this.onCocosCreated,
this.onCocosMessage,
this.fullscreen = false,
this.enablePlaceholder = false,
this.runImmediately = false,
this.unloadOnDispose = false,
this.printSetupLog = true,
this.onCocosUnloaded,
this.gestureRecognizers,
this.placeholder,
this.useAndroidViewSurface = false,
this.onCocosSceneLoaded,
this.uiLevel = 1,
this.borderRadius = BorderRadius.zero,
this.layoutDirection,
this.hideStatus = false,
});
///Event fires when the Cocos player is created.
final CocosCreatedCallback onCocosCreated;
///Event fires when the [CocosWidget] gets a message from Cocos.
final CocosMessageCallback? onCocosMessage;
///Event fires when the [CocosWidget] gets a scene loaded from Cocos.
final CocosSceneChangeCallback? onCocosSceneLoaded;
///Event fires when the [CocosWidget] Cocos player gets unloaded.
final CocosUnloadCallback? onCocosUnloaded;
final Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers;
/// Set to true to force Cocos to fullscreen
final bool fullscreen;
/// Set to true to force Cocos to fullscreen
final bool hideStatus;
/// Controls the layer in which Cocos widget is rendered in flutter (defaults to 1)
final int uiLevel;
/// This flag tells android to load Cocos as the flutter app starts (Android only)
final bool runImmediately;
/// This flag tells android to unload Cocos whenever widget is disposed
final bool unloadOnDispose;
/// This flag enables placeholder widget
final bool enablePlaceholder;
/// This flag enables placeholder widget
final bool printSetupLog;
/// This flag allows you use AndroidView instead of PlatformViewLink for android
final bool? useAndroidViewSurface;
/// This is just a helper to render a placeholder widget
final Widget? placeholder;
/// Border radius
final BorderRadius borderRadius;
/// The layout direction to use for the embedded view.
///
/// If this is null, the ambient [Directionality] is used instead. If there is
/// no ambient [Directionality], [TextDirection.ltr] is used.
final TextDirection? layoutDirection;
@override
_CocosWidgetState createState() => _CocosWidgetState();
}
class _CocosWidgetState extends State<CocosWidget> {
@override
Widget build(BuildContext context) {
return Text(
'$defaultTargetPlatform is not yet supported by the Cocos player plugin');
}
}

View File

@@ -0,0 +1,36 @@
import 'package:flutter_cocos_view/src/helpers/types.dart';
class CocosEvent<T> {
/// The ID of the Cocos this event is associated to.
final int cocosId;
/// The value wrapped by this event
final T value;
/// Build a Cocos Event, that relates a mapId with a given value.
///
/// The `cocosId` is the id of the map that triggered the event.
/// `value` may be `null` in events that don't transport any meaningful data.
CocosEvent(this.cocosId, this.value);
}
class CocosSceneLoadedEvent extends CocosEvent<SceneLoaded?> {
CocosSceneLoadedEvent(int cocosId, SceneLoaded? value)
: super(cocosId, value);
}
class CocosLoadedEvent extends CocosEvent<void> {
CocosLoadedEvent(int cocosId, void value) : super(cocosId, value);
}
class CocosUnLoadedEvent extends CocosEvent<void> {
CocosUnLoadedEvent(int cocosId, void value) : super(cocosId, value);
}
class CocosCreatedEvent extends CocosEvent<void> {
CocosCreatedEvent(int cocosId, void value) : super(cocosId, value);
}
class CocosMessageEvent extends CocosEvent<dynamic> {
CocosMessageEvent(int cocosId, dynamic value) : super(cocosId, value);
}

27
lib/src/helpers/misc.dart Normal file
View File

@@ -0,0 +1,27 @@
import 'package:flutter_cocos_view/src/helpers/types.dart';
/// Error thrown when an unknown cocos ID is provided to a method channel API.
class UnknownCocosIDError extends Error {
/// Creates an assertion error with the provided [cocosId] and optional
/// [message].
UnknownCocosIDError(this.cocosId, [this.message]);
/// The unknown ID.
final int cocosId;
/// Message describing the assertion error.
final Object? message;
String toString() {
if (message != null) {
return "Unknown cocos ID $cocosId: ${Error.safeToString(message)}";
}
return "Unknown cocos ID $cocosId";
}
}
typedef void CocosMessageCallback(dynamic handler);
typedef void CocosSceneChangeCallback(SceneLoaded? message);
typedef void CocosUnloadCallback();

View File

@@ -0,0 +1,31 @@
class SceneLoaded {
final String? name;
final int? buildIndex;
final bool? isLoaded;
final bool? isValid;
SceneLoaded({this.name, this.buildIndex, this.isLoaded, this.isValid});
/// Mainly for internal use when calling [CameraUpdate.newCameraPosition].
dynamic toMap() => <String, dynamic>{
'name': name,
'buildIndex': buildIndex,
'isLoaded': isLoaded,
'isValid': isValid,
};
/// Deserializes [SceneLoaded] from a map.
///
/// Mainly for internal use.
static SceneLoaded? fromMap(dynamic json) {
if (json == null) {
return null;
}
return SceneLoaded(
name: json['name'],
buildIndex: json['buildIndex'],
isLoaded: json['isLoaded'],
isValid: json['isValid'],
);
}
}

View File

@@ -0,0 +1,201 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import '../facade_controller.dart';
import '../helpers/misc.dart';
import 'device_method.dart';
import 'mobile_cocos_widget_controller.dart';
import 'cocos_widget_platform.dart';
int _nextCocosCreationId = 0;
/// Android specific settings for [CocosWidget].
class AndroidCocosWidgetFlutter {
/// Whether to render [CocosWidget] with a [AndroidViewSurface] to build the Flutter Cocos widget.
///
/// This implementation uses hybrid composition to render the Flutter Cocos
/// Widget on Android. This comes at the cost of some performance on Android
/// versions below 10. See
/// https://flutter.dev/docs/development/platform-integration/platform-views#performance for more
/// information.
///
/// Defaults to true.
static bool get useAndroidViewSurface {
final CocosWidgetPlatform platform = CocosWidgetPlatform.instance;
if (platform is MethodChannelCocosWidget) {
return platform.useAndroidViewSurface;
}
return false;
}
/// Set whether to render [CocosWidget] with a [AndroidViewSurface] to build the Flutter Cocos widget.
///
/// This implementation uses hybrid composition to render the Cocos Widget
/// Widget on Android. This comes at the cost of some performance on Android
/// versions below 10. See
/// https://flutter.dev/docs/development/platform-integration/platform-views#performance for more
/// information.
///
/// Defaults to true.
static set useAndroidViewSurface(bool useAndroidViewSurface) {
final CocosWidgetPlatform platform = CocosWidgetPlatform.instance;
if (platform is MethodChannelCocosWidget) {
platform.useAndroidViewSurface = useAndroidViewSurface;
}
}
}
typedef MobileCocosWidgetState = _CocosWidgetState;
class CocosWidget extends StatefulWidget {
CocosWidget({
Key? key,
required this.onCocosCreated,
this.onCocosMessage,
this.fullscreen = false,
this.enablePlaceholder = false,
this.runImmediately = false,
this.unloadOnDispose = false,
this.printSetupLog = true,
this.onCocosUnloaded,
this.gestureRecognizers,
this.placeholder,
this.useAndroidViewSurface = false,
this.onCocosSceneLoaded,
this.uiLevel = 1,
this.borderRadius = BorderRadius.zero,
this.layoutDirection,
this.hideStatus = false,
this.webUrl,
});
///Event fires when the Cocos player is created.
final CocosCreatedCallback onCocosCreated;
/// WebGL url source.
final String? webUrl;
///Event fires when the [CocosWidget] gets a message from Cocos.
final CocosMessageCallback? onCocosMessage;
///Event fires when the [CocosWidget] gets a scene loaded from Cocos.
final CocosSceneChangeCallback? onCocosSceneLoaded;
///Event fires when the [CocosWidget] Cocos player gets unloaded.
final CocosUnloadCallback? onCocosUnloaded;
final Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers;
/// Set to true to force Cocos to fullscreen
final bool fullscreen;
/// Set to true to force Cocos to fullscreen
final bool hideStatus;
/// Controls the layer in which Cocos widget is rendered in flutter (defaults to 1)
final int uiLevel;
/// This flag tells android to load Cocos as the flutter app starts (Android only)
final bool runImmediately;
/// This flag tells android to unload Cocos whenever widget is disposed
final bool unloadOnDispose;
/// This flag enables placeholder widget
final bool enablePlaceholder;
/// This flag enables placeholder widget
final bool printSetupLog;
/// This flag allows you use AndroidView instead of PlatformViewLink for android
final bool? useAndroidViewSurface;
/// This is just a helper to render a placeholder widget
final Widget? placeholder;
/// Border radius
final BorderRadius borderRadius;
/// The layout direction to use for the embedded view.
///
/// If this is null, the ambient [Directionality] is used instead. If there is
/// no ambient [Directionality], [TextDirection.ltr] is used.
final TextDirection? layoutDirection;
@override
_CocosWidgetState createState() => _CocosWidgetState();
}
class _CocosWidgetState extends State<CocosWidget> {
late int _cocosId;
CocosWidgetController? _controller;
@override
void initState() {
super.initState();
if (!kIsWeb) {
_cocosId = _nextCocosCreationId++;
} else {
_cocosId = 0;
}
}
@override
Future<void> dispose() async {
if (!kIsWeb) {
if (_nextCocosCreationId > 0) --_nextCocosCreationId;
}
try {
_controller?.dispose();
_controller = null;
} catch (e) {
// todo: implement
}
super.dispose();
}
@override
Widget build(BuildContext context) {
final Map<String, dynamic> cocosOptions = <String, dynamic>{
'fullscreen': widget.fullscreen,
'uiLevel': widget.uiLevel,
'hideStatus': widget.hideStatus,
'unloadOnDispose': widget.unloadOnDispose,
'runImmediately': widget.runImmediately,
};
if (widget.enablePlaceholder) {
return widget.placeholder ??
Text('Placeholder mode enabled, no native code will be called');
}
return CocosWidgetPlatform.instance.buildViewWithTextDirection(
_cocosId,
_onPlatformViewCreated,
cocosOptions: cocosOptions,
textDirection: widget.layoutDirection ??
Directionality.maybeOf(context) ??
TextDirection.ltr,
gestureRecognizers: widget.gestureRecognizers,
useAndroidViewSurf: widget.useAndroidViewSurface,
cocosSrcUrl: widget.webUrl,
);
}
Future<void> _onPlatformViewCreated(int id) async {
final controller = await MobileCocosWidgetController.init(id, this);
_controller = controller;
widget.onCocosCreated(controller);
if (widget.printSetupLog) {
log('*********************************************');
log('** flutter Cocos controller setup complete **');
log('*********************************************');
}
}
}

View File

@@ -0,0 +1,154 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import '../helpers/events.dart';
import 'device_method.dart';
abstract class CocosWidgetPlatform extends PlatformInterface {
/// Constructs a CocosViewFlutterPlatform.
CocosWidgetPlatform() : super(token: _token);
static final Object _token = Object();
static CocosWidgetPlatform _instance = MethodChannelCocosWidget();
/// The default instance of [CocosWidgetPlatform] to use.
///
/// Defaults to [MethodChannelCocosWidgetFlutter].
static CocosWidgetPlatform get instance => _instance;
/// Platform-specific plugins should set this with their own platform-specific
/// class that extends [CocosWidgetPlatform] when they register themselves.
static set instance(CocosWidgetPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
/// /// Initializes the platform interface with [id].
///
/// This method is called when the plugin is first initialized.
Future<void> init(int cocosId) {
throw UnimplementedError('init() has not been implemented.');
}
Future<bool?> isReady({required int cocosId}) async {
throw UnimplementedError('init() has not been implemented.');
}
Future<bool?> isPaused({required int cocosId}) async {
throw UnimplementedError('isPaused() has not been implemented.');
}
Future<bool?> isLoaded({required int cocosId}) async {
throw UnimplementedError('isLoaded() has not been implemented.');
}
Future<bool?> inBackground({required int cocosId}) async {
throw UnimplementedError('inBackground() has not been implemented.');
}
Future<bool?> createCocosPlayer({required int cocosId}) async {
throw UnimplementedError('createCocosPlayer() has not been implemented.');
}
Future<void> postMessage(
{required int cocosId,
required String gameObject,
required String methodName,
required String message}) {
throw UnimplementedError('postMessage() has not been implemented.');
}
Future<void> postJsonMessage(
{required int cocosId,
required String gameObject,
required String methodName,
required Map message}) {
throw UnimplementedError('postJsonMessage() has not been implemented.');
}
Future<void> pausePlayer({required int cocosId}) async {
throw UnimplementedError('pausePlayer() has not been implemented.');
}
Future<void> resumePlayer({required int cocosId}) async {
throw UnimplementedError('resumePlayer() has not been implemented.');
}
/// Opens cocos in it's own activity. Android only.
Future<void> openInNativeProcess({required int cocosId}) async {
throw UnimplementedError('openInNativeProcess() has not been implemented.');
}
Future<void> unloadPlayer({required int cocosId}) async {
throw UnimplementedError('unloadPlayer() has not been implemented.');
}
Future<void> quitPlayer({required int cocosId}) async {
throw UnimplementedError('quitPlayer() has not been implemented.');
}
Stream<CocosMessageEvent> onCocosMessage({required int cocosId}) {
throw UnimplementedError('onCocosMessage() has not been implemented.');
}
Stream<CocosLoadedEvent> onCocosUnloaded({required int cocosId}) {
throw UnimplementedError('onCocosUnloaded() has not been implemented.');
}
Stream<CocosCreatedEvent> onCocosCreated({required int cocosId}) {
throw UnimplementedError('onCocosUnloaded() has not been implemented.');
}
Stream<CocosSceneLoadedEvent> onCocosSceneLoaded({required int cocosId}) {
throw UnimplementedError('onCocosSceneLoaded() has not been implemented.');
}
/// Dispose of whatever resources the `cocosId` is holding on to.
void dispose({required int cocosId}) {
throw UnimplementedError('dispose() has not been implemented.');
}
/// Returns a widget displaying the cocos view
Widget buildView(
int creationId,
PlatformViewCreatedCallback onPlatformViewCreated, {
Map<String, dynamic> cocosOptions = const {},
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers,
bool? useAndroidViewSurf,
String? cocosSrcUrl,
}) {
throw UnimplementedError('buildView() has not been implemented.');
}
/// Returns a widget displaying the cocos view.
///
/// This method is similar to [buildView], but contains a parameter for
/// platforms that require a text direction.
///
/// Default behavior passes all parameters except `textDirection` to
/// [buildView]. This is for backward compatibility with existing
/// implementations. Platforms that use the text direction should override
/// this as the primary implementation, and delegate to it from buildView.
Widget buildViewWithTextDirection(
int creationId,
PlatformViewCreatedCallback onPlatformViewCreated, {
required TextDirection textDirection,
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers,
Map<String, dynamic> cocosOptions = const <String, dynamic>{},
bool? useAndroidViewSurf,
String? cocosSrcUrl,
}) {
return buildView(
creationId,
onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
cocosOptions: cocosOptions,
useAndroidViewSurf: useAndroidViewSurf,
cocosSrcUrl: cocosSrcUrl,
);
}
}

View File

@@ -0,0 +1,299 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:stream_transform/stream_transform.dart';
import '../helpers/events.dart';
import '../helpers/misc.dart';
import '../helpers/types.dart';
import 'cocos_widget_platform.dart';
import 'windows_cocos_widget_view.dart';
class MethodChannelCocosWidget extends CocosWidgetPlatform {
// Every method call passes the int cocosId
late final Map<int, MethodChannel> _channels = {};
/// Set [CocosWidgetFlutterPlatform] to use [AndroidViewSurface] to build the Google Maps widget.
///
/// This implementation uses hybrid composition to render the Cocos Widget
/// Widget on Android. This comes at the cost of some performance on Android
/// versions below 10. See
/// https://flutter.dev/docs/development/platform-integration/platform-views#performance for more
/// information.
/// Defaults to false.
bool useAndroidViewSurface = true;
/// Accesses the MethodChannel associated to the passed cocosId.
MethodChannel channel(int cocosId) {
MethodChannel? channel = _channels[cocosId];
if (channel == null) {
throw UnknownCocosIDError(cocosId);
}
return channel;
}
MethodChannel ensureChannelInitialized(int cocosId) {
MethodChannel? channel = _channels[cocosId];
if (channel == null) {
channel = MethodChannel('plugin.gem.com/cocos_view_$cocosId');
channel.setMethodCallHandler(
(MethodCall call) => _handleMethodCall(call, cocosId));
_channels[cocosId] = channel;
}
return channel;
}
/// Initializes the platform interface with [id].
///
/// This method is called when the plugin is first initialized.
@override
Future<void> init(int cocosId) {
MethodChannel channel = ensureChannelInitialized(cocosId);
return channel.invokeMethod<void>('cocos#waitForCocos');
}
/// Dispose of the native resources.
@override
Future<void> dispose({int? cocosId}) async {
try {
if (cocosId != null) await channel(cocosId).invokeMethod('cocos#dispose');
} catch (e) {
// ignore
}
}
// The controller we need to broadcast the different events coming
// from handleMethodCall.
//
// It is a `broadcast` because multiple controllers will connect to
// different stream views of this Controller.
final StreamController<CocosEvent> _cocosStreamController =
StreamController<CocosEvent>.broadcast();
// Returns a filtered view of the events in the _controller, by cocosId.
Stream<CocosEvent> _events(int cocosId) =>
_cocosStreamController.stream.where((event) => event.cocosId == cocosId);
Future<dynamic> _handleMethodCall(MethodCall call, int cocosId) async {
switch (call.method) {
case "events#onCocosMessage":
_cocosStreamController.add(CocosMessageEvent(cocosId, call.arguments));
break;
case "events#onCocosUnloaded":
_cocosStreamController.add(CocosLoadedEvent(cocosId, call.arguments));
break;
case "events#onCocosSceneLoaded":
_cocosStreamController.add(CocosSceneLoadedEvent(
cocosId, SceneLoaded.fromMap(call.arguments)));
break;
case "events#onCocosCreated":
_cocosStreamController.add(CocosCreatedEvent(cocosId, call.arguments));
break;
default:
throw UnimplementedError("Unimplemented ${call.method} method");
}
}
@override
Future<bool?> isPaused({required int cocosId}) async {
return await channel(cocosId).invokeMethod('cocos#isPaused');
}
@override
Future<bool?> isReady({required int cocosId}) async {
return await channel(cocosId).invokeMethod('cocos#isReady');
}
@override
Future<bool?> isLoaded({required int cocosId}) async {
return await channel(cocosId).invokeMethod('cocos#isLoaded');
}
@override
Future<bool?> inBackground({required int cocosId}) async {
return await channel(cocosId).invokeMethod('cocos#inBackground');
}
@override
Future<bool?> createCocosPlayer({required int cocosId}) async {
return await channel(cocosId).invokeMethod('cocos#createPlayer');
}
@override
Stream<CocosMessageEvent> onCocosMessage({required int cocosId}) {
return _events(cocosId).whereType<CocosMessageEvent>();
}
@override
Stream<CocosLoadedEvent> onCocosUnloaded({required int cocosId}) {
return _events(cocosId).whereType<CocosLoadedEvent>();
}
@override
Stream<CocosCreatedEvent> onCocosCreated({required int cocosId}) {
return _events(cocosId).whereType<CocosCreatedEvent>();
}
@override
Stream<CocosSceneLoadedEvent> onCocosSceneLoaded({required int cocosId}) {
return _events(cocosId).whereType<CocosSceneLoadedEvent>();
}
@override
Widget buildViewWithTextDirection(
int creationId,
PlatformViewCreatedCallback onPlatformViewCreated, {
required TextDirection textDirection,
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers,
Map<String, dynamic> cocosOptions = const <String, dynamic>{},
bool? useAndroidViewSurf,
bool? height,
bool? width,
bool? cocosWebSource,
String? cocosSrcUrl,
}) {
final String _viewType = 'plugin.gem.com/cocos_view';
if (useAndroidViewSurf != null) useAndroidViewSurface = useAndroidViewSurf;
final Map<String, dynamic> creationParams = cocosOptions;
if (defaultTargetPlatform == TargetPlatform.windows) {
return WindowsCocosWidgetView();
}
if (defaultTargetPlatform == TargetPlatform.android) {
if (!useAndroidViewSurface) {
return AndroidView(
viewType: _viewType,
onPlatformViewCreated: onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
layoutDirection: TextDirection.ltr,
);
}
return PlatformViewLink(
viewType: _viewType,
surfaceFactory: (
BuildContext context,
PlatformViewController controller,
) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: gestureRecognizers ??
const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
final controller = PlatformViewsService.initExpensiveAndroidView(
id: params.id,
viewType: _viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
onFocus: () => params.onFocusChanged(true),
);
controller
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..addOnPlatformViewCreatedListener(onPlatformViewCreated)
..create();
return controller;
},
);
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return UiKitView(
viewType: _viewType,
onPlatformViewCreated: onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}
return Text(
'$defaultTargetPlatform is not yet supported by the cocos player plugin');
}
@override
Widget buildView(
int creationId,
PlatformViewCreatedCallback onPlatformViewCreated, {
Map<String, dynamic> cocosOptions = const {},
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers,
bool? useAndroidViewSurf,
String? cocosSrcUrl,
}) {
return buildViewWithTextDirection(
creationId,
onPlatformViewCreated,
textDirection: TextDirection.ltr,
gestureRecognizers: gestureRecognizers,
cocosOptions: cocosOptions,
useAndroidViewSurf: useAndroidViewSurf,
cocosSrcUrl: cocosSrcUrl,
);
}
@override
Future<void> postMessage({
required int cocosId,
required String gameObject,
required String methodName,
required String message,
}) async {
await channel(cocosId).invokeMethod('cocos#postMessage', <String, dynamic>{
'gameObject': gameObject,
'methodName': methodName,
'message': message,
});
}
@override
Future<void> postJsonMessage({
required int cocosId,
required String gameObject,
required String methodName,
required Map message,
}) async {
await channel(cocosId).invokeMethod('cocos#postMessage', <String, dynamic>{
'gameObject': gameObject,
'methodName': methodName,
'message': json.encode(message),
});
}
@override
Future<void> pausePlayer({required int cocosId}) async {
await channel(cocosId).invokeMethod('cocos#pausePlayer');
}
@override
Future<void> resumePlayer({required int cocosId}) async {
await channel(cocosId).invokeMethod('cocos#resumePlayer');
}
@override
Future<void> openInNativeProcess({required int cocosId}) async {
await channel(cocosId).invokeMethod('cocos#openInNativeProcess');
}
@override
Future<void> unloadPlayer({required int cocosId}) async {
await channel(cocosId).invokeMethod('cocos#unloadPlayer');
}
@override
Future<void> quitPlayer({required int cocosId}) async {
await channel(cocosId).invokeMethod('cocos#quitPlayer');
}
}

4
lib/src/io/io.dart Normal file
View File

@@ -0,0 +1,4 @@
export '../facade_controller.dart';
export '../helpers/events.dart';
export '../helpers/misc.dart';
export '../helpers/types.dart';

View File

@@ -0,0 +1,213 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../facade_controller.dart';
import '../helpers/events.dart';
import 'device_method.dart';
import 'cocos_widget.dart';
import 'cocos_widget_platform.dart';
class MobileCocosWidgetController extends CocosWidgetController {
final MobileCocosWidgetState _cocosWidgetState;
/// The cocosId for this controller
final int cocosId;
/// used for cancel the subscription
StreamSubscription? _onCocosMessageSub,
_onCocosSceneLoadedSub,
_onCocosUnloadedSub;
MobileCocosWidgetController._(this._cocosWidgetState,
{required this.cocosId}) {
_connectStreams(cocosId);
}
/// Initialize [CocosWidgetController] with [id]
/// Mainly for internal use when instantiating a [CocosWidgetController] passed
/// in [CocosWidget.onCocosCreated] callback.
static Future<MobileCocosWidgetController> init(
int id, MobileCocosWidgetState cocosWidgetState) async {
await CocosWidgetPlatform.instance.init(id);
return MobileCocosWidgetController._(
cocosWidgetState,
cocosId: id,
);
}
@visibleForTesting
MethodChannel? get channel {
if (CocosWidgetPlatform.instance is MethodChannelCocosWidget) {
return (CocosWidgetPlatform.instance as MethodChannelCocosWidget)
.channel(cocosId);
}
return null;
}
void _connectStreams(int cocosId) {
if (_cocosWidgetState.widget.onCocosMessage != null) {
_onCocosMessageSub = CocosWidgetPlatform.instance
.onCocosMessage(cocosId: cocosId)
.listen((CocosMessageEvent e) =>
_cocosWidgetState.widget.onCocosMessage!(e.value));
}
if (_cocosWidgetState.widget.onCocosSceneLoaded != null) {
_onCocosSceneLoadedSub = CocosWidgetPlatform.instance
.onCocosSceneLoaded(cocosId: cocosId)
.listen((CocosSceneLoadedEvent e) =>
_cocosWidgetState.widget.onCocosSceneLoaded!(e.value));
}
if (_cocosWidgetState.widget.onCocosUnloaded != null) {
_onCocosUnloadedSub = CocosWidgetPlatform.instance
.onCocosUnloaded(cocosId: cocosId)
.listen((_) => _cocosWidgetState.widget.onCocosUnloaded!());
}
}
/// Checks to see if cocos player is ready to be used
/// Returns `true` if cocos player is ready.
Future<bool?>? isReady() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.isReady(cocosId: cocosId);
}
return null;
}
/// Get the current pause state of the cocos player
/// Returns `true` if cocos player is paused.
Future<bool?>? isPaused() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.isPaused(cocosId: cocosId);
}
return null;
}
/// Get the current load state of the cocos player
/// Returns `true` if cocos player is loaded.
Future<bool?>? isLoaded() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.isLoaded(cocosId: cocosId);
}
return null;
}
/// Helper method to know if Cocos has been put in background mode (WIP) unstable
/// Returns `true` if cocos player is in background.
Future<bool?>? inBackground() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.inBackground(cocosId: cocosId);
}
return null;
}
/// Creates a cocos player if it's not already created. Please only call this if cocos is not ready,
/// or is in unloaded state. Use [isLoaded] to check.
/// Returns `true` if cocos player was created succesfully.
Future<bool?>? create() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.createCocosPlayer(cocosId: cocosId);
}
return null;
}
/// Post message to cocos from flutter. This method takes in a string [message].
/// The [gameObject] must match the name of an actual cocos game object in a scene at runtime, and the [methodName],
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method
///
/// ```dart
/// postMessage("GameManager", "openScene", "ThirdScene")
/// ```
Future<void>? postMessage(String gameObject, methodName, message) {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.postMessage(
cocosId: cocosId,
gameObject: gameObject,
methodName: methodName,
message: message,
);
}
return null;
}
/// Post message to cocos from flutter. This method takes in a Json or map structure as the [message].
/// The [gameObject] must match the name of an actual cocos game object in a scene at runtime, and the [methodName],
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method
///
/// ```dart
/// postJsonMessage("GameManager", "openScene", {"buildIndex": 3, "name": "ThirdScene"})
/// ```
Future<void>? postJsonMessage(
String gameObject, String methodName, Map<String, dynamic> message) {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.postJsonMessage(
cocosId: cocosId,
gameObject: gameObject,
methodName: methodName,
message: message,
);
}
return null;
}
/// Pause the cocos in-game player with this method
Future<void>? pause() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.pausePlayer(cocosId: cocosId);
}
return null;
}
/// Resume the cocos in-game player with this method idf it is in a paused state
Future<void>? resume() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.resumePlayer(cocosId: cocosId);
}
return null;
}
/// Sometimes you want to open cocos in it's own process and openInNativeProcess does just that.
/// It works for Android and iOS is WIP
Future<void>? openInNativeProcess() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.openInNativeProcess(cocosId: cocosId);
}
return null;
}
/// Unloads cocos player from th current process (Works on Android only for now)
/// iOS is WIP. For more information please read [Cocos Docs](https://docs.cocos3d.com/2020.2/Documentation/Manual/CocosasaLibrary.html)
Future<void>? unload() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.unloadPlayer(cocosId: cocosId);
}
return null;
}
/// Quits cocos player. Note that this kills the current flutter process, thus quiting the app
Future<void>? quit() {
if (!_cocosWidgetState.widget.enablePlaceholder) {
return CocosWidgetPlatform.instance.quitPlayer(cocosId: cocosId);
}
return null;
}
/// cancel the subscriptions when dispose called
void _cancelSubscriptions() {
_onCocosMessageSub?.cancel();
_onCocosSceneLoadedSub?.cancel();
_onCocosUnloadedSub?.cancel();
_onCocosMessageSub = null;
_onCocosSceneLoadedSub = null;
_onCocosUnloadedSub = null;
}
void dispose() {
_cancelSubscriptions();
CocosWidgetPlatform.instance.dispose(cocosId: cocosId);
}
}

View File

@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
class WindowsCocosWidgetView extends StatefulWidget {
const WindowsCocosWidgetView({super.key});
@override
State<WindowsCocosWidgetView> createState() => _WindowsCocosWidgetViewState();
}
class _WindowsCocosWidgetViewState extends State<WindowsCocosWidgetView> {
@override
Widget build(BuildContext context) {
// TODO: Rex Update windows view
return const MouseRegion(
child: Texture(
textureId: 0,
),
);
}
}

View File

@@ -1,16 +1,18 @@
name: flutter_cocos_view name: flutter_cocos_view
description: "A new Flutter plugin project." description: "A new Flutter plugin project."
version: 0.0.1 version: 0.0.1
homepage: homepage: https://www.openim.io
environment: environment:
sdk: ^3.5.4 sdk: ">=3.0.0 <4.0.0"
flutter: '>=3.3.0' flutter: ">=1.20.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
plugin_platform_interface: ^2.0.2 plugin_platform_interface: ^2.0.2
stream_transform: ^2.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -33,14 +35,15 @@ flutter:
# All these are used by the tooling to maintain consistency when # All these are used by the tooling to maintain consistency when
# adding or updating assets for this project. # adding or updating assets for this project.
plugin: plugin:
platforms:
# This plugin project was generated without specifying any # This plugin project was generated without specifying any
# platforms with the `--platform` argument. If you see the `some_platform` map below, remove it and # platforms with the `--platform` argument. If you see the `some_platform` map below, remove it and
# then add platforms following the instruction here: # then add platforms following the instruction here:
# https://flutter.dev/to/pubspec-plugin-platforms # https://flutter.dev/to/pubspec-plugin-platforms
# ------------------- # -------------------
some_platform: platforms:
pluginClass: somePluginClass ios:
pluginClass: FlutterCocosWidgetPlugin
# ------------------- # -------------------
# To add assets to your plugin package, add an assets section, like this: # To add assets to your plugin package, add an assets section, like this:

View File

@@ -1,27 +0,0 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_cocos_view/flutter_cocos_view_method_channel.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
MethodChannelFlutterCocosView platform = MethodChannelFlutterCocosView();
const MethodChannel channel = MethodChannel('flutter_cocos_view');
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
(MethodCall methodCall) async {
return '42';
},
);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
});
test('getPlatformVersion', () async {
expect(await platform.getPlatformVersion(), '42');
});
}

View File

@@ -1,29 +0,0 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_cocos_view/flutter_cocos_view.dart';
import 'package:flutter_cocos_view/flutter_cocos_view_platform_interface.dart';
import 'package:flutter_cocos_view/flutter_cocos_view_method_channel.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
class MockFlutterCocosViewPlatform
with MockPlatformInterfaceMixin
implements FlutterCocosViewPlatform {
@override
Future<String?> getPlatformVersion() => Future.value('42');
}
void main() {
final FlutterCocosViewPlatform initialPlatform = FlutterCocosViewPlatform.instance;
test('$MethodChannelFlutterCocosView is the default instance', () {
expect(initialPlatform, isInstanceOf<MethodChannelFlutterCocosView>());
});
test('getPlatformVersion', () async {
FlutterCocosView flutterCocosViewPlugin = FlutterCocosView();
MockFlutterCocosViewPlatform fakePlatform = MockFlutterCocosViewPlatform();
FlutterCocosViewPlatform.instance = fakePlatform;
expect(await flutterCocosViewPlugin.getPlatformVersion(), '42');
});
}