Flutter游戏集成插件flutter_unity_widget_pro的使用
Flutter游戏集成插件flutter_unity_widget_pro的使用
flutter_unity_widget_pro
Flutter unity 3D widget for embedding unity in flutter. Now you can make awesome gamified features of your app in Unity and get it rendered in a Flutter app both in fullscreen and embeddable mode. Works great on Android, iPad OS, iOS, Web, with Windows
nearing completion. There are now two unity app examples in the unity folder, one with the default scene and another based on Unity AR foundation samples.
注意:仅支持Unity 2019.4.3或更高版本。UnityFramework不支持模拟器。 注意:目前仅支持在Android上使用OpenGLES3作为Graphics API。
注意
需要我回复,请@Rex Isaac Raphael。 始终使用与你使用的Unity版本匹配的FUW unitypackage。
此插件假定你至少知道如何使用Unity引擎。如果你对Unity widget的展示方式有疑问,你可以根据需要修改你的Unity项目构建设置。
未来版本号将根据Unity版本进行更改。请注意,这并不意味着该包不兼容其他版本,而只是表示它已经过测试以与特定Unity版本一起工作。
Windows即将推出。
^2022.1.0+5支持Flutter 3.0.0,并且现在只能使用PlatformViewSurface
。这意味着你必须在UnityWidget
中传递useAndroidViewSurface: true
。你可以跟踪这个问题。
目前正在进行支持AndroidView的工作。
安装
首先,在你的pubspec.yaml
文件中添加依赖项:
Flutter 3.0.0
dependencies:
flutter_unity_widget_pro: ^2022.2.0
Pre Flutter 3.0.0(此版本将逐渐被弃用)
dependencies:
flutter_unity_widget_pro: ^2022.1.0+7
现在可以在你的Dart代码中导入它:
import 'package:flutter_unity_widget_pro/flutter_unity_widget_pro.dart';
预览
以下是展示Flutter和Unity之间通信的30帧GIF:
设置
对于此,还有一个视频教程,你可以在这里找到。
在以下教程中,有针对每个平台的具体步骤,由一个 ℹ️ 图标后跟平台名称(Android或iOS)标记。你可以点击图标展开它。
前提条件
- 一个现有的Flutter项目(如果没有,可以创建一个新的)
- 一个现有的Unity项目(如果没有,可以创建一个新的)
- 一个FlutterUnityPackage.unitypackage 文件(你也可以访问unitypackages文件夹中的Unity包) 记住始终检查与你的项目匹配的unitypackage。
NDK
如果您的项目需要Android NDK,需要进行以下设置:
你的Android项目需要知道Unity使用的NDK路径。你可以在Preferences -> External Tools
下找到NDK路径:
[NDK Path]
通过右键单击并复制路径,将其粘贴到你的android/local.properties
文件中:
ndk.dir=/Applications/Unity/Hub/Editor/2020.3.19f1/PlaybackEngines/AndroidPlayer/NDK
就这样!你不需要在你的app/build.gradle
文件中告诉你的Android应用NDK版本或其他NDK设置。现在它已经与Unity连接上了。
步骤
-
创建一个名为
unity
的文件夹,并将Unity项目移动到其中。预期路径为
unity/<project-name>/...
-
将
FlutterUnityPackage.unitypackage
文件复制到Unity项目文件夹中。预期路径为
unity/<project-name>/FlutterUnityPackage.unitypackage
-
使用Unity打开Unity项目,转到
File > Build Settings > Player Settings
,并在Configuration
部分更改以下内容:- 在
Scripting Backend
中,更改为IL2CPP - 在
Target Architectures
中,选择ARMv7和ARM64
信息来源:iOS 根据你想测试或运行应用的位置(模拟器或物理设备),选择适当的SDK。
确保至少有一个场景已添加到你的构建中。
- 在
-
转到
Assets > Import Package > Custom Package
并选择FlutterUnityPackage.unitypackage
文件。点击Import
。 -
导入后,点击
Flutter
并选择Export Android Debug
或Export Android Release
选项(将导出到android/unityLibrary
)或Export iOS Debug
或Export iOS Release
选项(将导出到ios/UnityLibrary
)。不要使用
Flutter > Export <Platform> plugin
,因为它专门用于与flutter_unity_cli配合使用大型项目。信息来源:Android 导出脚本会自动为你设置好,所以你无需手动设置Android。但如果你想手动设置,继续操作。
6.1 打开
android/settings.gradle
文件并更改以下内容:+ include ":unityLibrary" + project(":unityLibrary").projectDir = file("./unityLibrary")
6.2 打开
android/app/build.gradle
文件并更改以下内容:dependencies { + implementation project(':unityLibrary') }
6.3 如果你需要构建一个发布包,打开
android/app/build.gradle
文件并更改以下内容:buildTypes { release { signingConfig signingConfigs.debug } + debug { + signingConfig signingConfigs.debug + } + profile { + signingConfig signingConfigs.debug + } + innerTest { + matchingFallbacks = ['debug', 'release'] + } + }
上述代码使用
debug
签名配置应用于所有构建类型,你可以根据需要更改签名配置。6.4 如果你在
android/app/build.gradle
文件中使用了minifyEnabled true
,打开android/unityLibrary/proguard-unity.txt
并更改以下内容:+ -keep class com.xraph.plugin.** {*;}
6.5 如果你想让Unity在一个单独的活动中作为替代,打开
android/app/src/main/AndroidManifest.xml
并更改以下内容:+ <activity + android:name="com.xraph.plugin.flutter_unity_widget_pro.OverrideUnityActivity" + android:theme="[@style](/user/style)/UnityThemeSelector" + android:screenOrientation="fullSensor" + android:launchMode="singleTask" + android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" + android:hardwareAccelerated="false" + android:process=":Unity"> + <meta-data android:name="com.xraph.plugin.flutter_unity_widget_pro.OverrideUnityActivity" android:value="true" /> + </activity>
信息来源:iOS 6.1 在Xcode中打开
ios/Runner.xcworkspace
(工作区,不是项目)文件,右键点击导航器(不是项目项),转到Add Files to "Runner"
并添加ios/UnityLibrary/Unity-Iphone.xcodeproj
文件。6.2 (可选)选择
Unity-iPhone/Data
文件夹并将目标成员关系更改为UnityFramework
。6.3.1 如果你正在使用Swift,打开
ios/Runner/AppDelegate.swift
文件并更改以下内容:import UIKit import Flutter + import flutter_unity_widget_pro @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + InitUnityIntegrationWithOptions(argc: CommandLine.argc, argv: CommandLine.unsafeArgv, launchOptions) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } }
6.3.2 如果你正在使用Objective-C,打开
ios/Runner/main.m
文件并更改以下内容:+ #import "flutter_unity_widget_pro.swift.h" int main(int argc, char * argv[]) { @autoreleasepool { + InitUnityIntegration(argc, argv); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
6.4 打开
ios/Runner/Info.plist
并更改以下内容:<dict> + <key>io.flutter.embedded_views_preview</key> + <string>YES</string> </dict>
6.5 将
UnityFramework.framework
文件作为库添加到Runner项目中。
AR Foundation 设置
查看Unity AR Foundation示例。 此存储库不一定与最新的
flutter-unity-view-widget
主分支保持一致。确保遵循以下步骤在你的项目中设置AR Foundation。
信息来源:Android
-
打开
lib/<architecture>/
文件夹并检查是否同时存在libUnityARCore.so
和libarpresto_api.so
文件。 似乎有一个bug,Unity导出时可能不会包含所有库文件。如果它们缺失,请使用Unity构建一个独立的.apk,解压生成的apk,并将缺失的.lib文件复制到unityLibrary
模块。 -
对于Android,重复步骤6.1和6.2,将
unityLibrary
替换为arcore_client
,unityandroidpermissions
和UnityARCore
。 -
当在Flutter中使用
UnityWidget
时,设置fullscreen: false
以禁用全屏模式。
信息来源:iOS
- 打开
ios/Runner/Info.plist
并更改以下内容:
<dict>
+ <key>Privacy - Camera Usage Description</key>
+ <string>$(PRODUCT_NAME) uses Cameras</string>
</dict>
Vuforia 设置
感谢@PiotrxKolasinski编写了详细的步骤:
- 打开
android/unityLibrary/build.gradle
文件并更改以下内容:
- implementation(name: 'VuforiaWrapper', ext: 'aar')
+ implementation project(':VuforiaWrapper')
-
使用Android Studio,转到
File > Open
并选择android/
文件夹。一个新项目将会打开。不要担心如果出现错误消息“Project with path ‘:VuforiaWrapper’ could not be found in project ‘:unityLibrary’”,下一步将解决这个问题。
-
在这个新的项目窗口中,转到
File > New > New Module > Import .JAR/.AAR package
并选择android/unityLibrary/libs/VuforiaWrapper.aar
文件。一个名为VuforiaWrapper
的新文件夹将会在android/
中创建。你现在可以关闭这个新的项目窗口。
通信
Flutter-Unity
-
在
UnityWidget
小部件上,获取onUnityCreated
回调接收到的UnityWidgetController
。 -
使用
postMessage
方法发送字符串,使用GameObject名称和应调用的行为方法名称。
Unity-Flutter
-
选择应执行通信的GameObject并转到
Inspector > Add Component > Unity Message Manager
。 -
创建一个新的
MonoBehaviour
子类并将其作为脚本添加到同一个GameObject中。 -
在这个新行为中,调用
GetComponent<UnityMessageManager>()
来获取一个UnityMessageManager
。 -
使用
SendMessageToFlutter
方法发送字符串。使用UnityWidget
的onUnityMessage
回调接收此消息。
故障排除
位置:Unity
错误:
InvalidOperationException: The build target does not support build appending.
解决方案:
- 打开
unity/<project-name>/Assets/FlutterUnityIntegration/Editor/Build.cs
文件。
1.1 在第48行更改以下内容:
- var options = BuildOptions.AcceptExternalModificationsToPlayer;
+ var options = BuildOptions.AllowDebugging;
+ EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
1.2 在第115行更改以下内容:
- var options = BuildOptions.AcceptExternalModificationsToPlayer;
+ var options = BuildOptions.AllowDebugging;
位置:Android Studio
错误:
minSdkVersion XX cannot be smaller than version 19 declared in library
\ [:flutter_unity_widget_pro] .../AndroidManifest.xml as the library might be using
\ APIs not available in XX
解决方案:
- 打开
android/app/build.gradle
文件并更改以下内容:
- minSdkVersion XX
+ minSdkVersion 19
位置:Android Studio
错误:
e: .../FlutterUnityWidgetBuilder.kt: (15, 42): Expecting a parameter declaration
e: .../FlutterUnityWidgetBuilder.kt: (23, 25): Expecting an argument
e: .../FlutterUnityWidgetController.kt: (22, 44): Expecting a parameter declaration
e: .../FlutterUnityWidgetFactory.kt: (13, 58): Expecting a parameter declaration
解决方案:
- 打开
android/build.gradle
文件并更改以下内容:
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '1.4.31'
位置:Android Studio
错误:
Unable to find a matching variant of project :unityLibrary:
解决方案:
- 打开
android/app/build.gradle
文件并更改以下内容:
lintOptions {
disable 'InvalidPackage'
+ checkReleaseBuilds false
}
示例
简单示例
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_unity_widget_pro/flutter_unity_widget_pro.dart';
void main() {
runApp(MaterialApp(
home: UnityDemoScreen()
));
}
class UnityDemoScreen extends StatefulWidget {
UnityDemoScreen({Key key}) : super(key: key);
@override
_UnityDemoScreenState createState() => _UnityDemoScreenState();
}
class _UnityDemoScreenState extends State<UnityDemoScreen>{
static final GlobalKey<ScaffoldState> _scaffoldKey =
GlobalKey<ScaffoldState>();
UnityWidgetController _unityWidgetController;
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
bottom: false,
child: WillPopScope(
onWillPop: () {
// Pop the category page if Android back button is pressed.
},
child: Container(
color: Colors.yellow,
child: UnityWidget(
onUnityCreated: onUnityCreated,
),
),
),
),
);
}
// 回调函数,将创建的控制器连接到Unity控制器
void onUnityCreated(controller) {
this._unityWidgetController = controller;
}
}
与Unity双向通信
import 'package:flutter/material.dart';
import 'package:flutter_unity_widget_pro/flutter_unity_widget_pro.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
static final GlobalKey<ScaffoldState> _scaffoldKey =
GlobalKey<ScaffoldState>();
UnityWidgetController _unityWidgetController;
double _sliderValue = 0.0;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('Unity Flutter Demo'),
),
body: Card(
margin: const EdgeInsets.all(8),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: <Widget>[
UnityWidget(
onUnityCreated: onUnityCreated,
onUnityMessage: onUnityMessage,
onUnitySceneLoaded: onUnitySceneLoaded,
fullscreen: false,
),
Positioned(
bottom: 20,
left: 20,
right: 20,
child: Card(
elevation: 10,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text("Rotation speed:"),
),
Slider(
onChanged: (value) {
setState(() {
_sliderValue = value;
});
setRotationSpeed(value.toString());
},
value: _sliderValue,
min: 0,
max: 20,
),
],
),
),
),
],
),
),
),
);
}
// 从Flutter向Unity发送消息
void setRotationSpeed(String speed) {
_unityWidgetController.postMessage(
'Cube',
'SetRotationSpeed',
speed,
);
}
// 从Unity向Flutter发送消息
void onUnityMessage(message) {
print('Received message from unity: ${message.toString()}');
}
// 回调函数,将创建的控制器连接到Unity控制器
void onUnityCreated(controller) {
this._unityWidgetController = controller;
}
// 从Unity加载新场景时向Flutter发送消息
void onUnitySceneLoaded(SceneLoaded sceneInfo) {
print('Received scene loaded from unity: ${sceneInfo.name}');
print('Received scene loaded from unity buildIndex: ${sceneInfo.buildIndex}');
}
}
属性
fullscreen
(启用或禁用Android上的全屏模式)
API
pause()
(使用此方法暂停Unity播放器)resume()
(使用此方法恢复Unity播放器)unload()
(使用此方法卸载Unity播放器) *需要Unity 2019.4.3或更高版本quit()
(使用此方法退出Unity播放器)postMessage(String gameObject, methodName, message)
(允许你从Flutter调用Unity中的命令)onUnityMessage(data)
(Unity到Flutter绑定和监听器)onUnityUnloaded()
(Unity到Flutter监听器当Unity卸载时)onUnitySceneLoaded(String name, int buildIndex, bool isLoaded, bool isValid,)
(Unity到Flutter绑定和监听器当新场景加载时)
flavors
推荐
应用口味的最简单方法是:flutter_flavorizr。
如果你在应用中使用了口味,你可能会注意到特别是iOS在运行或构建应用时崩溃! 以下是应用口味的必要步骤:
Android
无需任何额外设置,口味已自动应用。
iOS
对于你的Unity iOS构建,你必须将口味添加到Unity iOS配置中。
-
检查你当前的
Runner
(你的应用)配置。例如,如果你有口味:- dev
- prod
你的
Runner
配置看起来像这样:因此你有口味:
Debug-dev
Profile-dev
Release-dev
Debug-prod
Profile-prod
Release-prod
这些口味需要添加到你的
Unity-IPhone
项目中。 -
进入你的
Unity-IPhone
项目 - > PROJECTUnity-IPhone
- > Info:在配置部分,你只能看到:
Release
ReleaseForProfiling
ReleaseForRunning
Debug
-
复制
Debug
配置两次,并重命名为Debug-dev
和Debug-prod
。你可以通过选择
+
并复制配置来完成,如下所示: -
重复此操作,将
Release
复制到Release-dev
和Release-prod
。 -
重复此操作,将
Release
复制到Profile-dev
和Profile-prod
。 -
你的
Unity-IPhone
配置现在应该看起来像这样:
Web
默认情况下,Flutter不支持--flavor
用于构建Web。但是,你可以在运行和构建时设置你的目标main.dart
入口点(使用-t main.dart
)。因此,如果你正确设置了口味,则无需对Web进行任何更改即可应用对你Flutter-Unity Web应用的更改。
已知问题
- 记住在Unity玩家设置中禁用全屏以禁用Unity全屏。
- Unity在Android上冻结并崩溃,请使用OpenGL3作为Graphics API。
- 由于你的Unity项目中的一些本地依赖项导致项目构建失败,请在Android或iOS上集成这些依赖项的本地库。
- 应用在屏幕退出和重新进入时崩溃,请执行以下操作:
Build Setting - iOS - Other Settings - Configuration - Enable Custom Background Behaviors or iOS
- Android构建在Unity 2022.1.*上花费很长时间,请从
unityLibrary/build.gradle
文件中删除以下行:commandLineArgs.add("--enable-debugger") commandLineArgs.add("--profiler-report") commandLineArgs.add("--profiler-output-file=" + workingDir + "/build/il2cpp_" + abi + "_" + configuration + "/il2cpp_conv.traceevents")
更多关于Flutter游戏集成插件flutter_unity_widget_pro的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter游戏集成插件flutter_unity_widget_pro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter项目中集成flutter_unity_widget_pro
插件以嵌入Unity游戏内容,可以按照以下步骤进行。以下是一个基本的代码案例,帮助你理解如何设置和使用该插件。
步骤 1: 添加依赖
首先,在你的pubspec.yaml
文件中添加flutter_unity_widget_pro
依赖:
dependencies:
flutter:
sdk: flutter
flutter_unity_widget_pro: ^版本号 # 替换为最新的版本号
然后运行flutter pub get
来安装依赖。
步骤 2: 配置Unity项目
- 创建Unity项目:在你的计算机上安装Unity并创建一个新的Unity项目。
- 构建Unity项目:在Unity中,选择
File
>Build Settings
,然后选择Android
或iOS
平台,并确保已正确配置SDK路径。点击Build
并选择一个文件夹来保存构建的Unity库文件(通常是.aar
文件用于Android或.framework
文件用于iOS)。
步骤 3: 将Unity库文件添加到Flutter项目
- 对于Android:将生成的
.aar
文件及其依赖项(如libs
文件夹中的其他.aar
文件)复制到Flutter项目的android/app/libs
目录中。然后在android/app/build.gradle
文件中添加以下代码以包含这些库:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar'])
// 其他依赖项...
}
- 对于iOS:将生成的Unity
.framework
文件复制到Flutter项目的ios/Frameworks
目录中(如果没有该目录,请创建它)。然后,在Xcode中,将.framework
文件添加到你的Flutter iOS项目中,并确保在Build Phases
的Link Binary with Libraries
部分中包含了它。
步骤 4: 使用flutter_unity_widget_pro
插件
在你的Flutter代码中,你可以使用FlutterUnityWidget
来嵌入Unity视图。以下是一个简单的示例:
import 'package:flutter/material.dart';
import 'package:flutter_unity_widget_pro/flutter_unity_widget_pro.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Unity Integration'),
),
body: Center(
child: UnityWidget(
onUnityMessage: (message) {
print('Unity -> Flutter: $message');
},
onUnityCreated: (controller) {
// 可以在这里调用Unity的方法
// controller.send('MethodName', 'param1', 'param2');
},
onUnityViewCreated: () {
print('Unity view created');
},
onUnityResumed: () {
print('Unity resumed');
},
onUnityPaused: () {
print('Unity paused');
},
onUnityDestroyed: () {
print('Unity destroyed');
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 这里可以添加一些按钮来与Unity交互
// 例如,发送消息给Unity
},
tooltip: 'Interact with Unity',
child: Icon(Icons.play_arrow),
),
),
);
}
}
步骤 5: 运行Flutter项目
确保你已经正确配置了Android或iOS的开发环境,然后运行你的Flutter项目:
flutter run
这个示例展示了如何在Flutter应用中嵌入Unity视图,并通过回调与Unity进行通信。根据你的具体需求,你可能需要调整Unity项目的设置,或者扩展Flutter与Unity之间的通信逻辑。