Merge branch 'original-master'
* original-master: (34 commits) Update README.md Update README.md Update README.md update contributors Create CODE_OF_CONDUCT.md bump release version new release 0.1.6+1 Adding Metal renderer support (on iOS) Update README.md Update README.md Update .all-contributorsrc Update CHANGELOG.md update contributors updated changelog made new release with support for iOS Docs: Add @krispypen as a contributor added contributors Added iOS gif Docs: Add @thomas-stockx as a contributor Docs: Add @juicycleff as a contributor ...
This commit is contained in:
commit
d7ecc5d139
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"projectName": "flutter-unity-view-widget",
|
||||
"projectOwner": "snowballdigital",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"files": [
|
||||
"README.md"
|
||||
],
|
||||
"imageSize": 100,
|
||||
"commit": true,
|
||||
"commitConvention": "eslint",
|
||||
"contributors": [
|
||||
{
|
||||
"login": "juicycleff",
|
||||
"name": "Rex Raphael",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/11243590?v=4",
|
||||
"profile": "http://rexraphael.com",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"question",
|
||||
"bug",
|
||||
"review",
|
||||
"tutorial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "thomas-stockx",
|
||||
"name": "Thomas Stockx",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/1475368?v=4",
|
||||
"profile": "https://stockxit.com",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"question",
|
||||
"tutorial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "krispypen",
|
||||
"name": "Kris Pypen",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/156955?v=4",
|
||||
"profile": "http://krispypen.github.io/",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"question",
|
||||
"tutorial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lorant-csonka-planorama",
|
||||
"name": "Lorant Csonka",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/48209860?v=4",
|
||||
"profile": "https://github.com/lorant-csonka-planorama",
|
||||
"contributions": [
|
||||
"doc",
|
||||
"video"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7
|
||||
}
|
|
@ -16,6 +16,10 @@
|
|||
*.iws
|
||||
.idea/
|
||||
|
||||
node_modules/
|
||||
./package.json
|
||||
.idea/
|
||||
|
||||
# Visual Studio Code related
|
||||
.vscode/
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.0 MiB |
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -1,12 +1,23 @@
|
|||
## 0.1.6+1
|
||||
|
||||
* Adding Metal renderer support (on iOS) [@krispypen](https://github.com/krispypen)
|
||||
|
||||
## 0.1.6
|
||||
|
||||
* iOS support for the Unity 2019.3 new export format Unity as a Library [@krispypen](https://github.com/krispypen)
|
||||
|
||||
## 0.1.5
|
||||
|
||||
* Android support for the Unity 2019.3 new export format Unity as a Library [@thomas-stockx](https://github.com/thomas-stockx)
|
||||
|
||||
## 0.1.4
|
||||
|
||||
* Support for AR on Android thanks to @thomas-stockx
|
||||
|
||||
* Support for AR on Android thanks to [@thomas-stockx](https://github.com/thomas-stockx)
|
||||
|
||||
## 0.1.3+4
|
||||
|
||||
* Change input source of Flutter touch events so they work in Unity @thomas-stockx
|
||||
* Change input source of Flutter touch events so they work in Unity [@thomas-stockx](https://github.com/thomas-stockx)
|
||||
* Instructions on how to implement Vuforia AR
|
||||
* Fix postMessage throwing exceptions on Android @thomas-stockx
|
||||
* Add video tutorial, replace `unity-player` with `unity-classes` in example
|
||||
* Remove java and UnityPlayer changes to the windowmanager
|
||||
* Fix postMessage throwing exceptions on Android [@thomas-stockx](https://github.com/thomas-stockx)
|
||||
* Add video tutorial, replace `unity-player` with `unity-classes` in example [@lorant-csonka-planorama](https://github.com/lorant-csonka-planorama)
|
||||
* Remove java and UnityPlayer changes to the windowmanager [@thomas-stockx](https://github.com/thomas-stockx)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at rex@snowball.digital. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
90
README.md
90
README.md
|
@ -1,4 +1,5 @@
|
|||
# flutter_unity_widget
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)
|
||||
|
||||
[![version][version-badge]][package]
|
||||
[![MIT License][license-badge]][license]
|
||||
|
@ -7,14 +8,14 @@
|
|||
[![Watch on GitHub][github-watch-badge]][github-watch]
|
||||
[![Star on GitHub][github-star-badge]][github-star]
|
||||
|
||||
Flutter unity 3D widget for embedding unity in flutter. Add a Flutter widget to show unity. Works on Android, iOS in works.
|
||||
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 and iOS.
|
||||
|
||||
## Installation
|
||||
First depend on the library by adding this to your packages `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter_unity_widget: ^0.1.4
|
||||
flutter_unity_widget: ^0.1.6+1
|
||||
```
|
||||
|
||||
Now inside your Dart code you can import it.
|
||||
|
@ -26,7 +27,10 @@ import 'package:flutter_unity_widget/flutter_unity_widget.dart';
|
|||
|
||||
## Preview
|
||||
|
||||
![gif](https://github.com/snowballdigital/flutter-unity-view-widget/blob/master/2019_03_28_19_23_37.gif?raw=true)
|
||||
30 fps gifs, showcasing communication between Flutter and Unity:
|
||||
|
||||
![gif](https://github.com/snowballdigital/flutter-unity-view-widget/blob/master/preview_android.gif?raw=true)
|
||||
![gif](https://github.com/snowballdigital/flutter-unity-view-widget/blob/master/preview_ios.gif?raw=true)
|
||||
|
||||
<br />
|
||||
|
||||
|
@ -57,9 +61,11 @@ Now your project files should look like this.
|
|||
|
||||
1. First Open Unity Project.
|
||||
|
||||
2. Click Menu: File => Build Settings => Player Settings
|
||||
2. Click Menu: File => Build Settings
|
||||
|
||||
3. Change `Product Name` to Name of the Xcode project, You can find it follow `ios/${XcodeProjectName}.xcodeproj`.
|
||||
Be sure you have at least one scene added to your build.
|
||||
|
||||
3. => Player Settings
|
||||
|
||||
**Android Platform**:
|
||||
1. Make sure your `Graphics APIs` are set to OpenGLES3 with a fallback to OpenGLES2 (no Vulkan)
|
||||
|
@ -71,22 +77,20 @@ Now your project files should look like this.
|
|||
- ARM64 ✅
|
||||
- x86 ✅
|
||||
|
||||
<img src="https://raw.githubusercontent.com/snowballdigital/flutter-unity-view-widget/master/Screenshot%202019-03-27%2007.31.55.png" width="400" />
|
||||
|
||||
**IOS Platform**:
|
||||
1. Other Settings find the Rendering part, uncheck the `Auto Graphics API` and select only `OpenGLES2`.
|
||||
**iOS Platform**:
|
||||
1. This only works with Unity version >=2019.3 because uses Unity as a library!
|
||||
2. Depending on where you want to test or run your app, (simulator or physical device), you should select the appropriate SDK on `Target SDK`.
|
||||
<br />
|
||||
|
||||
|
||||
<img src="https://raw.githubusercontent.com/snowballdigital/flutter-unity-view-widget/master/Screenshot%202019-03-27%2007.31.55.png" width="400" />
|
||||
|
||||
<br />
|
||||
|
||||
### Add Unity Build Scripts and Export
|
||||
|
||||
Copy [`Build.cs`](https://github.com/f111fei/react-native-unity-demo/blob/master/unity/Cube/Assets/Scripts/Editor/Build.cs) and [`XCodePostBuild.cs`](https://github.com/f111fei/react-native-unity-demo/blob/master/unity/Cube/Assets/Scripts/Editor/XCodePostBuild.cs) to `unity/<Your Unity Project>/Assets/Scripts/Editor/`
|
||||
Copy [`Build.cs`](https://github.com/snowballdigital/flutter-unity-view-widget/tree/master/scripts/Editor/Build.cs) and [`XCodePostBuild.cs`](https://github.com/snowballdigital/flutter-unity-view-widget/tree/master/scripts/Editor/XCodePostBuild.cs) to `unity/<Your Unity Project>/Assets/Scripts/Editor/`
|
||||
|
||||
Open your unity project in Unity Editor. Now you can export unity project with `Flutter/Export Android` or `Flutter/Export IOS` menu.
|
||||
Open your unity project in Unity Editor. Now you can export the Unity project with `Flutter/Export Android` (for Unity versions up to 2019.2), `Flutter/Export Android (Unity 2019.3.*)` (for Unity versions 2019.3 and up, which uses the new [Unity as a Library](https://blogs.unity3d.com/2019/06/17/add-features-powered-by-unity-to-native-mobile-apps/) export format), or `Flutter/Export IOS` menu.
|
||||
|
||||
<img src="https://github.com/snowballdigital/flutter-unity-view-widget/blob/master/Screenshot%202019-03-27%2008.13.08.png?raw=true" width="400" />
|
||||
|
||||
|
@ -99,20 +103,13 @@ IOS will export unity project to `ios/UnityExport`.
|
|||
**Android Platform Only**
|
||||
|
||||
1. After exporting the unity game, open Android Studio and and add the `Unity Classes` Java `.jar` file as a module to the unity project. You just need to do this once if you are exporting from the same version of Unity everytime. The `.jar` file is located in the ```<Your Flutter Project>/android/UnityExport/lib``` folder
|
||||
2. Next open `build.gradle` of `flutter_unity_widget` module and replace the dependencies with
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation project(':UnityExport') // The exported unity project
|
||||
implementation project(':unity-classes') // the unity classes module you added from step 1
|
||||
}
|
||||
```
|
||||
3. Next open `build.gradle` of `UnityExport` module and replace the dependencies with
|
||||
2. If using Unity 2019.2 or older, open `build.gradle` of `UnityExport` module and replace the dependencies with
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation project(':unity-classes') // the unity classes module you added from step 1
|
||||
}
|
||||
```
|
||||
4. Next open `build.gradle` of `UnityExport` module and remove these
|
||||
3. If using Unity 2019.2 or older, open `build.gradle` of `UnityExport` module and remove these
|
||||
```gradle
|
||||
bundle {
|
||||
language {
|
||||
|
@ -127,9 +124,31 @@ IOS will export unity project to `ios/UnityExport`.
|
|||
}
|
||||
```
|
||||
|
||||
**iOS Platform Only**
|
||||
|
||||
1. open your ios/Runner.xcworkspace (workspace!, not the project) in Xcode and add the exported project in the workspace root (with a right click in the Navigator, not on an item -> Add Files to “Runner” -> add the UnityExport/Unity-Iphone.xcodeproj file
|
||||
<img src="workspace.png" width="400" />
|
||||
2. Select the Unity-iPhone/Data folder and change the Target Membership for Data folder to UnityFramework
|
||||
<img src="change_target_membership_data_folder.png" width="400" />
|
||||
3. Add this to your Runner/Runner/Runner-Bridging-Header.h
|
||||
|
||||
```c
|
||||
#import "UnityUtils.h"
|
||||
```
|
||||
4. Add to AppDelegate.swift before the GeneratePluginRegistrant call:
|
||||
|
||||
```swift
|
||||
InitArgs(CommandLine.argc, CommandLine.unsafeArgv)
|
||||
```
|
||||
5. Opt-in to the embedded views preview by adding a boolean property to the app's `Info.plist` file with the key `io.flutter.embedded_views_preview` and the value `YES`.
|
||||
|
||||
<br />
|
||||
|
||||
### AR Foundation (ANDROID only at the moment)
|
||||
### AR Foundation (not compatible with Unity 2019.3)
|
||||
https://github.com/Unity-Technologies/arfoundation-samples/issues/210
|
||||
|
||||
Android only as iOS requires Unity 2019.3.
|
||||
|
||||
If you want to use Unity for integrating Augmented Reality in your Flutter app, a few more changes are required:
|
||||
1. Export the Unity Project as previously stated (using the Editor Build script).
|
||||
2. Check if the exported project includes all required Unity libraries (.so) files (`lib/\<architecture\>/libUnityARCore.so` and `libarpresto_api.so`). There seems to be a bug where a Unity export does not include all lib files. If they are missing, use Unity to build a standalone .apk of your AR project, unzip the resulting apk, and copy over the missing .lib files to the `UnityExport` module.
|
||||
|
@ -276,15 +295,16 @@ class _UnityDemoScreenState extends State<UnityDemoScreen>{
|
|||
## API
|
||||
- `pause()` (Use this to pause unity player)
|
||||
- `resume()` (Use this to resume unity player)
|
||||
- `postMessage(String gameObject, methodName, message)` (Allows you invoke commands in Unity from flutter)
|
||||
- `onUnityMessage(data)` (Unity to flutter bindding and listener)
|
||||
|
||||
## Known issues
|
||||
- no iOS support yet
|
||||
- Android Export requires several manual changes
|
||||
- Using AR will make the activity run in full screen (hiding status and navigation bar).
|
||||
|
||||
|
||||
[version-badge]: https://img.shields.io/pub/v/flutter_unity_widget.svg?style=flat-square
|
||||
[package]: https://pub.dartlang.org/packages/flutter_unity_widget/versions/0.1.2
|
||||
[package]: https://pub.dartlang.org/packages/flutter_unity_widget/
|
||||
[license-badge]: https://img.shields.io/github/license/snowballdigital/flutter-unity-view-widget.svg?style=flat-square
|
||||
[license]: https://github.com/snowballdigital/flutter-unity-view-widget/blob/master/LICENSE
|
||||
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
|
||||
|
@ -293,3 +313,25 @@ class _UnityDemoScreenState extends State<UnityDemoScreen>{
|
|||
[github-watch]: https://github.com/snowballdigital/flutter-unity-view-widget/watchers
|
||||
[github-star-badge]: https://img.shields.io/github/stars/snowballdigital/flutter-unity-view-widget.svg?style=social
|
||||
[github-star]: https://github.com/snowballdigital/flutter-unity-view-widget/stargazers
|
||||
|
||||
## Contributors ✨
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://rexraphael.com"><img src="https://avatars2.githubusercontent.com/u/11243590?v=4" width="100px;" alt="Rex Raphael"/><br /><sub><b>Rex Raphael</b></sub></a><br /><a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=juicycleff" title="Code">💻</a> <a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=juicycleff" title="Documentation">📖</a> <a href="#question-juicycleff" title="Answering Questions">💬</a> <a href="https://github.com/snowballdigital/flutter-unity-view-widget/issues?q=author%3Ajuicycleff" title="Bug reports">🐛</a> <a href="#review-juicycleff" title="Reviewed Pull Requests">👀</a> <a href="#tutorial-juicycleff" title="Tutorials">✅</a></td>
|
||||
<td align="center"><a href="https://stockxit.com"><img src="https://avatars1.githubusercontent.com/u/1475368?v=4" width="100px;" alt="Thomas Stockx"/><br /><sub><b>Thomas Stockx</b></sub></a><br /><a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=thomas-stockx" title="Code">💻</a> <a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=thomas-stockx" title="Documentation">📖</a> <a href="#question-thomas-stockx" title="Answering Questions">💬</a> <a href="#tutorial-thomas-stockx" title="Tutorials">✅</a></td>
|
||||
<td align="center"><a href="http://krispypen.github.io/"><img src="https://avatars1.githubusercontent.com/u/156955?v=4" width="100px;" alt="Kris Pypen"/><br /><sub><b>Kris Pypen</b></sub></a><br /><a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=krispypen" title="Code">💻</a> <a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=krispypen" title="Documentation">📖</a> <a href="#question-krispypen" title="Answering Questions">💬</a> <a href="#tutorial-krispypen" title="Tutorials">✅</a></td>
|
||||
<td align="center"><a href="https://github.com/lorant-csonka-planorama"><img src="https://avatars2.githubusercontent.com/u/48209860?v=4" width="100px;" alt="Lorant Csonka"/><br /><sub><b>Lorant Csonka</b></sub></a><br /><a href="https://github.com/snowballdigital/flutter-unity-view-widget/commits?author=lorant-csonka-planorama" title="Documentation">📖</a> <a href="#video-lorant-csonka-planorama" title="Videos">📹</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
|
@ -1 +1 @@
|
|||
eb7addd6604d08d1b14bdd2f0b7568eea6aaad77
|
||||
5c787ba36b071ef6ee6a4f60499357697d53c75b
|
||||
|
|
Binary file not shown.
|
@ -1 +1 @@
|
|||
1d70ee33aab6965c19c5636e539561c5c25ac66b
|
||||
bd1065d7afc1a8da0fc454a1d7dede98f3aaa473
|
||||
|
|
Binary file not shown.
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// Created by rex on 19/03/2019.
|
||||
//
|
||||
|
||||
#ifndef FLUTTER_UNITY_WIDGET_FLUTTERUNITY_H
|
||||
#define FLUTTER_UNITY_WIDGET_FLUTTERUNITY_H
|
||||
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
@interface FlutterUnityController : NSObject <FlutterPlatformView>
|
||||
|
||||
- (instancetype)initWithWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
|
||||
|
||||
- (UIView*)view;
|
||||
@end
|
||||
|
||||
@interface FlutterUnityFactory : NSObject <FlutterPlatformViewFactory>
|
||||
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
|
||||
@end
|
||||
|
||||
#endif //FLUTTER_UNITY_WIDGET_FLUTTERUNITY_H
|
|
@ -1,87 +0,0 @@
|
|||
//
|
||||
// Created by rex on 19/03/2019.
|
||||
//
|
||||
|
||||
#include "FlutterUnity.h"
|
||||
|
||||
@implementation FlutterUnityFactory {
|
||||
NSObject<FlutterBinaryMessenger>* _messenger;
|
||||
}
|
||||
|
||||
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_messenger = messenger;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@implementation FlutterUnityController {
|
||||
WKWebView* _webView;
|
||||
int64_t _viewId;
|
||||
FlutterMethodChannel* _channel;
|
||||
}
|
||||
|
||||
- (instancetype)initWithWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
|
||||
if ([super init]) {
|
||||
_viewId = viewId;
|
||||
_webView = [[WKWebView alloc] initWithFrame:frame];
|
||||
NSString* channelName = [NSString stringWithFormat:@"nativeweb_%lld", viewId];
|
||||
_channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:messenger];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
|
||||
[weakSelf onMethodCall:call result:result];
|
||||
}];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView*)view {
|
||||
return _webView;
|
||||
}
|
||||
|
||||
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
if ([[call method] isEqualToString:@"postMessage"]) {
|
||||
[self postMessage:call result:result];
|
||||
} else if ([[call method] isEqualToString:@"isReady"]) {
|
||||
[self postMessage:call result:result];
|
||||
} else if ([[call method] isEqualToString:@"createUnity"]) {
|
||||
[self postMessage:call result:result];
|
||||
} else if ([[call method] isEqualToString:@"pause"]) {
|
||||
[self postMessage:call result:result];
|
||||
} else if ([[call method] isEqualToString:@"resume"]) {
|
||||
[self postMessage:call result:result];
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)postMessage:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
NSString* url = [call arguments];
|
||||
if (![self postMessage:url]) {
|
||||
result([FlutterError errorWithCode:@"loadUrl_failed"
|
||||
message:@"Failed parsing the URL"
|
||||
details:[NSString stringWithFormat:@"URL was: '%@'", url]]);
|
||||
} else {
|
||||
result(nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)onPostMessage:(NSString*)url {
|
||||
NSURL* nsUrl = [NSURL URLWithString:url];
|
||||
if (!nsUrl) {
|
||||
return false;
|
||||
}
|
||||
NSURLRequest* req = [NSURLRequest requestWithURL:nsUrl];
|
||||
[_webView loadRequest:req];
|
||||
return true;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// FlutterUnityView.h
|
||||
// FlutterUnityView
|
||||
//
|
||||
// Created by krispypen on 8/1/2019
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "UnityUtils.h"
|
||||
|
||||
@interface FlutterUnityView : UIView
|
||||
|
||||
@property (nonatomic, strong) UIView* uView;
|
||||
|
||||
- (void)setUnityView:(UIView *)view;
|
||||
|
||||
@end
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// FlutterUnityView.m
|
||||
// FlutterUnityView
|
||||
//
|
||||
// Created by krispypen on 8/1/2019
|
||||
//
|
||||
|
||||
#import "FlutterUnityView.h"
|
||||
|
||||
@implementation FlutterUnityView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setUnityView:(UIView *)view
|
||||
{
|
||||
self.uView = view;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
[(UIView *)self.uView removeFromSuperview];
|
||||
[self insertSubview:(UIView *)self.uView atIndex:0];
|
||||
((UIView *)self.uView).frame = self.bounds;
|
||||
[(UIView *)self.uView setNeedsLayout];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,4 +1,25 @@
|
|||
//
|
||||
// FlutterUnityWidgetPlugin.h
|
||||
// FlutterUnityWidgetPlugin
|
||||
//
|
||||
// Created by Kris Pypen on 8/1/19.
|
||||
//
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
@interface FlutterUnityWidgetPlugin : NSObject<FlutterPlugin>
|
||||
@end
|
||||
|
||||
@interface FUController : NSObject <FlutterPlatformView>
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
registrar:(NSObject<FlutterPluginRegistrar> *)registrar;
|
||||
|
||||
- (UIView*)view;
|
||||
@end
|
||||
|
||||
@interface FUViewFactory : NSObject <FlutterPlatformViewFactory>
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar;
|
||||
@end
|
||||
|
|
|
@ -1,20 +1,106 @@
|
|||
//
|
||||
// FlutterUnityWidgetPlugin.m
|
||||
// FlutterUnityWidgetPlugin
|
||||
//
|
||||
// Created by Kris Pypen on 8/1/19.
|
||||
//
|
||||
|
||||
#import "FlutterUnityWidgetPlugin.h"
|
||||
#import <flutter_unity_widget/flutter_unity_widget-Swift.h>
|
||||
#import "UnityUtils.h"
|
||||
#import "FlutterUnityView.h"
|
||||
|
||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
FlutterNativeWebFactory* webviewFactory =
|
||||
[[FlutterNativeWebFactory alloc] initWithMessenger:registrar.messenger];
|
||||
[registrar registerViewFactory:webviewFactory withId:@"unity_view"];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
#import "FlutterUnityWidgetPlugin.h"
|
||||
#import <flutter_unity_widget/flutter_unity_widget-Swift.h>
|
||||
#include <UnityFramework/UnityFramework.h>
|
||||
|
||||
@implementation FlutterUnityWidgetPlugin
|
||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
[SwiftFlutterUnityWidgetPlugin registerWithRegistrar:registrar];
|
||||
FUViewFactory* fuviewFactory = [[FUViewFactory alloc] initWithRegistrar:registrar];
|
||||
[registrar registerViewFactory:fuviewFactory withId:@"unity_view"];
|
||||
}
|
||||
@end
|
||||
*/
|
||||
|
||||
@implementation FUViewFactory {
|
||||
NSObject<FlutterPluginRegistrar>* _registrar;
|
||||
}
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_registrar = registrar;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
|
||||
return [FlutterStandardMessageCodec sharedInstance];
|
||||
}
|
||||
|
||||
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args {
|
||||
FUController* controller = [[FUController alloc] initWithFrame:frame
|
||||
viewIdentifier:viewId
|
||||
arguments:args
|
||||
registrar:_registrar];
|
||||
return controller;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUController {
|
||||
FlutterUnityView* _uView;
|
||||
int64_t _viewId;
|
||||
FlutterMethodChannel* _channel;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
if ([super init]) {
|
||||
_viewId = viewId;
|
||||
|
||||
NSString* channelName = [NSString stringWithFormat:@"unity_view_%lld", viewId];
|
||||
_channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:registrar.messenger];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
|
||||
[weakSelf onMethodCall:call result:result];
|
||||
}];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
if ([[call method] isEqualToString:@"postMessage"]) {
|
||||
[self postMessage:call result:result];
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)postMessage:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
NSString* object = [call arguments][@"gameObject"];
|
||||
NSString* method = [call arguments][@"methodName"];
|
||||
NSString* message = [call arguments][@"message"];
|
||||
|
||||
UnityPostMessage(object, method, message);
|
||||
|
||||
result(nil);
|
||||
}
|
||||
|
||||
- (UIView*)view {
|
||||
_uView = [[FlutterUnityView alloc] init];
|
||||
if ([UnityUtils isUnityReady]) {
|
||||
[_uView setUnityView: (UIView*)[GetAppController() unityView]];
|
||||
} else {
|
||||
[UnityUtils createPlayer:^{
|
||||
[_uView setUnityView: (UIView*)[GetAppController() unityView]];
|
||||
}];
|
||||
}
|
||||
return _uView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,27 +1,23 @@
|
|||
//
|
||||
// Created by rex on 15/03/2019.
|
||||
//
|
||||
|
||||
#ifndef FLUTTER_UNITY_WIDGET_UNITYUTILS_H
|
||||
#define FLUTTER_UNITY_WIDGET_UNITYUTILS_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifndef UnityUtils_h
|
||||
#define UnityUtils_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void InitArgs(int argc, char* argv[]);
|
||||
void InitArgs(int argc, char* argv[]);
|
||||
|
||||
bool UnityIsInited(void);
|
||||
bool UnityIsInited(void);
|
||||
|
||||
void InitUnity();
|
||||
void InitUnity();
|
||||
|
||||
void UnityPostMessage(NSString* gameObject, NSString* methodName, NSString* message);
|
||||
void UnityPostMessage(NSString* gameObject, NSString* methodName, NSString* message);
|
||||
|
||||
void UnityPauseCommand();
|
||||
void UnityPauseCommand();
|
||||
|
||||
void UnityResumeCommand();
|
||||
void UnityResumeCommand();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -40,5 +36,4 @@ void UnityResumeCommand();
|
|||
|
||||
@end
|
||||
|
||||
#endif //FLUTTER_UNITY_WIDGET_UNITYUTILS_H
|
||||
|
||||
#endif /* UnityUtils_h */
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#include "RegisterMonoModules.h"
|
||||
#include "RegisterFeatures.h"
|
||||
#include <csignal>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "UnityInterface.h"
|
||||
#import "UnityUtils.h"
|
||||
#import "UnityAppController.h"
|
||||
|
||||
#include <UnityFramework/UnityFramework.h>
|
||||
|
||||
// Hack to work around iOS SDK 4.3 linker problem
|
||||
// we need at least one __TEXT, __const section entry in main application .o files
|
||||
|
@ -18,6 +16,8 @@ char** g_argv;
|
|||
|
||||
void UnityInitTrampoline();
|
||||
|
||||
UnityFramework* ufw;
|
||||
|
||||
extern "C" void InitArgs(int argc, char* argv[])
|
||||
{
|
||||
g_argc = argc;
|
||||
|
@ -29,6 +29,19 @@ extern "C" bool UnityIsInited()
|
|||
return unity_inited;
|
||||
}
|
||||
|
||||
UnityFramework* UnityFrameworkLoad()
|
||||
{
|
||||
NSString* bundlePath = nil;
|
||||
bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
bundlePath = [bundlePath stringByAppendingString: @"/Frameworks/UnityFramework.framework"];
|
||||
|
||||
NSBundle* bundle = [NSBundle bundleWithPath: bundlePath];
|
||||
if ([bundle isLoaded] == false) [bundle load];
|
||||
|
||||
UnityFramework* ufw = [bundle.principalClass getInstance];
|
||||
return ufw;
|
||||
}
|
||||
|
||||
extern "C" void InitUnity()
|
||||
{
|
||||
if (unity_inited) {
|
||||
|
@ -36,41 +49,30 @@ extern "C" void InitUnity()
|
|||
}
|
||||
unity_inited = true;
|
||||
|
||||
UnityInitStartupTime();
|
||||
ufw = UnityFrameworkLoad();
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
UnityInitTrampoline();
|
||||
UnityInitRuntime(g_argc, g_argv);
|
||||
|
||||
RegisterMonoModules();
|
||||
NSLog(@"-> registered mono modules %p\n", &constsection);
|
||||
RegisterFeatures();
|
||||
|
||||
// iOS terminates open sockets when an application enters background mode.
|
||||
// The next write to any of such socket causes SIGPIPE signal being raised,
|
||||
// even if the request has been done from scripting side. This disables the
|
||||
// signal and allows Mono to throw a proper C# exception.
|
||||
std::signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
[ufw setDataBundleId: "com.unity3d.framework"];
|
||||
[ufw frameworkWarmup: g_argc argv: g_argv];
|
||||
}
|
||||
|
||||
extern "C" void UnityPostMessage(NSString* gameObject, NSString* methodName, NSString* message)
|
||||
{
|
||||
UnitySendMessage([gameObject UTF8String], [methodName UTF8String], [message UTF8String]);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[ufw sendMessageToGOWithName:[gameObject UTF8String] functionName:[methodName UTF8String] message:[message UTF8String]];
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" void UnityPauseCommand()
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UnityPause(1);
|
||||
[ufw pause:true];
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" void UnityResumeCommand()
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UnityPause(0);
|
||||
[ufw pause:false];
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,11 @@ Flutter unity 3D widget for embedding unity in flutter
|
|||
s.source_files = 'Classes/**/*'
|
||||
s.public_header_files = 'Classes/**/*.h'
|
||||
s.dependency 'Flutter'
|
||||
s.frameworks = 'UnityFramework'
|
||||
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.xcconfig = {
|
||||
'FRAMEWORK_SEARCH_PATHS' => '"${PODS_ROOT}/../UnityExport" "${PODS_ROOT}/../.symlinks/flutter/ios-release" "${PODS_CONFIGURATION_BUILD_DIR}"',
|
||||
'OTHER_LDFLAGS' => '$(inherited) -framework UnityFramework ${PODS_LIBRARIES}'
|
||||
}
|
||||
end
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.4 MiB |
Binary file not shown.
After Width: | Height: | Size: 8.3 MiB |
|
@ -1,8 +1,10 @@
|
|||
name: flutter_unity_widget
|
||||
description: Flutter unity 3D widget for embedding unity in flutter
|
||||
version: 0.1.4
|
||||
version: 0.1.6+1
|
||||
authors:
|
||||
- Rex Raphael <rex.raphael@outlook.com>
|
||||
- Thomas Stockx <thomas@stockxit.com>
|
||||
- Kris Pypen <kris.pypen@gmail.com>
|
||||
homepage: https://github.com/snowballdigital/flutter-unity-view-widget/tree/master
|
||||
|
||||
environment:
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Application = UnityEngine.Application;
|
||||
using BuildResult = UnityEditor.Build.Reporting.BuildResult;
|
||||
|
||||
public class Build : MonoBehaviour
|
||||
{
|
||||
static readonly string ProjectPath = Path.GetFullPath(Path.Combine(Application.dataPath, ".."));
|
||||
|
||||
static readonly string apkPath = Path.Combine(ProjectPath, "Builds/" + Application.productName + ".apk");
|
||||
|
||||
static readonly string androidExportPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../android/UnityExport"));
|
||||
static readonly string iosExportPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../ios/UnityExport"));
|
||||
|
||||
[MenuItem("Flutter/Export Android (Unity 2019.3.*) %&n", false, 1)]
|
||||
public static void DoBuildAndroidLibrary()
|
||||
{
|
||||
DoBuildAndroid(Path.Combine(apkPath, "unityLibrary"));
|
||||
|
||||
// Copy over resources from the launcher module that are used by the library
|
||||
Copy(Path.Combine(apkPath + "/launcher/src/main/res"), Path.Combine(androidExportPath, "src/main/res"));
|
||||
}
|
||||
|
||||
[MenuItem("Flutter/Export Android %&a", false, 2)]
|
||||
public static void DoBuildAndroidLegacy()
|
||||
{
|
||||
DoBuildAndroid(Path.Combine(apkPath, Application.productName));
|
||||
}
|
||||
|
||||
public static void DoBuildAndroid(String buildPath)
|
||||
{
|
||||
if (Directory.Exists(apkPath))
|
||||
Directory.Delete(apkPath, true);
|
||||
|
||||
if (Directory.Exists(androidExportPath))
|
||||
Directory.Delete(androidExportPath, true);
|
||||
|
||||
EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
|
||||
|
||||
var options = BuildOptions.AcceptExternalModificationsToPlayer;
|
||||
var report = BuildPipeline.BuildPlayer(
|
||||
GetEnabledScenes(),
|
||||
apkPath,
|
||||
BuildTarget.Android,
|
||||
options
|
||||
);
|
||||
|
||||
if (report.summary.result != BuildResult.Succeeded)
|
||||
throw new Exception("Build failed");
|
||||
|
||||
Copy(buildPath, androidExportPath);
|
||||
|
||||
// Modify build.gradle
|
||||
var build_file = Path.Combine(androidExportPath, "build.gradle");
|
||||
var build_text = File.ReadAllText(build_file);
|
||||
build_text = build_text.Replace("com.android.application", "com.android.library");
|
||||
build_text = build_text.Replace("implementation fileTree(dir: 'libs', include: ['*.jar'])", "implementation project(':unity-classes')");
|
||||
build_text = Regex.Replace(build_text, @"\n.*applicationId '.+'.*\n", "\n");
|
||||
File.WriteAllText(build_file, build_text);
|
||||
|
||||
// Modify AndroidManifest.xml
|
||||
var manifest_file = Path.Combine(androidExportPath, "src/main/AndroidManifest.xml");
|
||||
var manifest_text = File.ReadAllText(manifest_file);
|
||||
manifest_text = Regex.Replace(manifest_text, @"<application .*>", "<application>");
|
||||
Regex regex = new Regex(@"<activity.*>(\s|\S)+?</activity>", RegexOptions.Multiline);
|
||||
manifest_text = regex.Replace(manifest_text, "");
|
||||
File.WriteAllText(manifest_file, manifest_text);
|
||||
}
|
||||
|
||||
[MenuItem("Flutter/Export IOS (Unity 2019.3.*) %&i", false, 3)]
|
||||
public static void DoBuildIOS()
|
||||
{
|
||||
if (Directory.Exists(iosExportPath))
|
||||
Directory.Delete(iosExportPath, true);
|
||||
|
||||
EditorUserBuildSettings.iOSBuildConfigType = iOSBuildType.Release;
|
||||
|
||||
var options = BuildOptions.AcceptExternalModificationsToPlayer;
|
||||
var report = BuildPipeline.BuildPlayer(
|
||||
GetEnabledScenes(),
|
||||
iosExportPath,
|
||||
BuildTarget.iOS,
|
||||
options
|
||||
);
|
||||
|
||||
if (report.summary.result != BuildResult.Succeeded)
|
||||
throw new Exception("Build failed");
|
||||
}
|
||||
|
||||
static void Copy(string source, string destinationPath)
|
||||
{
|
||||
if (Directory.Exists(destinationPath))
|
||||
Directory.Delete(destinationPath, true);
|
||||
|
||||
Directory.CreateDirectory(destinationPath);
|
||||
|
||||
foreach (string dirPath in Directory.GetDirectories(source, "*",
|
||||
SearchOption.AllDirectories))
|
||||
Directory.CreateDirectory(dirPath.Replace(source, destinationPath));
|
||||
|
||||
foreach (string newPath in Directory.GetFiles(source, "*.*",
|
||||
SearchOption.AllDirectories))
|
||||
File.Copy(newPath, newPath.Replace(source, destinationPath), true);
|
||||
}
|
||||
|
||||
static string[] GetEnabledScenes()
|
||||
{
|
||||
var scenes = EditorBuildSettings.scenes
|
||||
.Where(s => s.enabled)
|
||||
.Select(s => s.path)
|
||||
.ToArray();
|
||||
|
||||
return scenes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
MIT License
|
||||
Copyright (c) 2017 Jiulong Wang
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#if UNITY_IOS
|
||||
|
||||
using System;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.iOS.Xcode;
|
||||
|
||||
/// <summary>
|
||||
/// Adding this post build script to Unity project enables the flutter-unity-widget to access it
|
||||
/// </summary>
|
||||
public static class XcodePostBuild
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The identifier added to touched file to avoid double edits when building to existing directory without
|
||||
/// replace existing content.
|
||||
/// </summary>
|
||||
private const string TouchedMarker = "https://github.com/snowballdigital/flutter-unity-view-widget";
|
||||
|
||||
[PostProcessBuild]
|
||||
public static void OnPostBuild(BuildTarget target, string pathToBuiltProject)
|
||||
{
|
||||
if (target != BuildTarget.iOS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PatchUnityNativeCode(pathToBuiltProject);
|
||||
|
||||
UpdateUnityProjectFiles(pathToBuiltProject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We need to add the Data folder to the UnityFramework framework
|
||||
/// </summary>
|
||||
private static void UpdateUnityProjectFiles(string pathToBuiltProject)
|
||||
{
|
||||
var pbx = new PBXProject();
|
||||
var pbxPath = Path.Combine(pathToBuiltProject, "Unity-iPhone.xcodeproj/project.pbxproj");
|
||||
pbx.ReadFromFile(pbxPath);
|
||||
|
||||
// Add UnityExport/Data
|
||||
var targetGuid = pbx.TargetGuidByName("UnityFramework");
|
||||
var fileGuid = pbx.AddFolderReference(Path.Combine(pathToBuiltProject, "Data"), "Data");
|
||||
pbx.AddFileToBuild(targetGuid, fileGuid);
|
||||
|
||||
pbx.WriteToFile(pbxPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make necessary changes to Unity build output that enables it to be embedded into existing Xcode project.
|
||||
/// </summary>
|
||||
private static void PatchUnityNativeCode(string pathToBuiltProject)
|
||||
{
|
||||
EditUnityFrameworkH(Path.Combine(pathToBuiltProject, "UnityFramework/UnityFramework.h"));
|
||||
EditUnityAppControllerH(Path.Combine(pathToBuiltProject, "Classes/UnityAppController.h"));
|
||||
EditUnityAppControllerMM(Path.Combine(pathToBuiltProject, "Classes/UnityAppController.mm"));
|
||||
EditUnityViewMM(Path.Combine(pathToBuiltProject, "Classes/UI/UnityView.mm"));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Edit 'UnityFramework.h': add 'frameworkWarmup'
|
||||
/// </summary>
|
||||
private static void EditUnityFrameworkH(string path)
|
||||
{
|
||||
var inScope = false;
|
||||
|
||||
// Add frameworkWarmup method
|
||||
EditCodeFile(path, line =>
|
||||
{
|
||||
inScope |= line.Contains("- (void)runUIApplicationMainWithArgc:");
|
||||
|
||||
if (inScope)
|
||||
{
|
||||
if (line.Trim() == "")
|
||||
{
|
||||
inScope = false;
|
||||
|
||||
return new string[]
|
||||
{
|
||||
"",
|
||||
"// Added by " + TouchedMarker,
|
||||
"- (void)frameworkWarmup:(int)argc argv:(char*[])argv;",
|
||||
""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new string[] { line };
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Edit 'UnityAppController.h': returns 'UnityAppController' from 'AppDelegate' class.
|
||||
/// </summary>
|
||||
private static void EditUnityAppControllerH(string path)
|
||||
{
|
||||
var inScope = false;
|
||||
var markerDetected = false;
|
||||
|
||||
// Add static GetAppController
|
||||
EditCodeFile(path, line =>
|
||||
{
|
||||
inScope |= line.Contains("- (void)startUnity:");
|
||||
|
||||
if (inScope)
|
||||
{
|
||||
if (line.Trim() == "")
|
||||
{
|
||||
inScope = false;
|
||||
|
||||
return new string[]
|
||||
{
|
||||
"",
|
||||
"// Added by " + TouchedMarker,
|
||||
"+ (UnityAppController*)GetAppController;",
|
||||
""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new string[] { line };
|
||||
});
|
||||
|
||||
inScope = false;
|
||||
markerDetected = false;
|
||||
|
||||
// Modify inline GetAppController
|
||||
EditCodeFile(path, line =>
|
||||
{
|
||||
inScope |= line.Contains("extern UnityAppController* GetAppController");
|
||||
|
||||
if (inScope && !markerDetected)
|
||||
{
|
||||
if (line.Trim() == "")
|
||||
{
|
||||
inScope = false;
|
||||
markerDetected = true;
|
||||
|
||||
return new string[]
|
||||
{
|
||||
"// }",
|
||||
"",
|
||||
"static inline UnityAppController* GetAppController()",
|
||||
"{",
|
||||
" return [UnityAppController GetAppController];",
|
||||
"}",
|
||||
};
|
||||
}
|
||||
|
||||
return new string[] { "// " + line };
|
||||
}
|
||||
|
||||
return new string[] { line };
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Edit 'UnityAppController.mm': triggers 'UnityReady' notification after Unity is actually started.
|
||||
/// </summary>
|
||||
private static void EditUnityAppControllerMM(string path)
|
||||
{
|
||||
var inScope = false;
|
||||
var markerDetected = false;
|
||||
|
||||
EditCodeFile(path, line =>
|
||||
{
|
||||
if (line.Trim() == "@end")
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"",
|
||||
"// Added by " + TouchedMarker,
|
||||
"static UnityAppController *unityAppController = nil;",
|
||||
"",
|
||||
@"+ (UnityAppController*)GetAppController",
|
||||
"{",
|
||||
" static dispatch_once_t onceToken;",
|
||||
" dispatch_once(&onceToken, ^{",
|
||||
" unityAppController = [[self alloc] init];",
|
||||
" });",
|
||||
" return unityAppController;",
|
||||
"}",
|
||||
"",
|
||||
line,
|
||||
};
|
||||
}
|
||||
|
||||
inScope |= line.Contains("- (void)startUnity:");
|
||||
markerDetected |= inScope && line.Contains(TouchedMarker);
|
||||
|
||||
if (inScope && line.Trim() == "}")
|
||||
{
|
||||
inScope = false;
|
||||
|
||||
if (markerDetected)
|
||||
{
|
||||
return new string[] { line };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
" // Modified by " + TouchedMarker,
|
||||
@" [[NSNotificationCenter defaultCenter] postNotificationName: @""UnityReady"" object:self];",
|
||||
"}",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new string[] { line };
|
||||
});
|
||||
|
||||
inScope = false;
|
||||
markerDetected = false;
|
||||
|
||||
// Modify inline GetAppController
|
||||
EditCodeFile(path, line =>
|
||||
{
|
||||
inScope |= line.Contains("UnityAppController* GetAppController()");
|
||||
|
||||
if (inScope && !markerDetected)
|
||||
{
|
||||
if (line.Trim() == "}")
|
||||
{
|
||||
inScope = false;
|
||||
markerDetected = true;
|
||||
|
||||
return new string[]
|
||||
{
|
||||
"",
|
||||
};
|
||||
}
|
||||
|
||||
return new string[] { "// " + line };
|
||||
}
|
||||
|
||||
return new string[] { line };
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Edit 'UnityView.mm': fix the width and height needed for the Metal renderer
|
||||
/// </summary>
|
||||
private static void EditUnityViewMM(string path)
|
||||
{
|
||||
var inScope = false;
|
||||
|
||||
// Add frameworkWarmup method
|
||||
EditCodeFile(path, line =>
|
||||
{
|
||||
inScope |= line.Contains("UnityGetRenderingResolution(&requestedW, &requestedH)");
|
||||
|
||||
if (inScope)
|
||||
{
|
||||
if (line.Trim() == "")
|
||||
{
|
||||
inScope = false;
|
||||
|
||||
return new string[]
|
||||
{
|
||||
"",
|
||||
"// Added by " + TouchedMarker,
|
||||
" if (requestedW == 0) {",
|
||||
" requestedW = _surfaceSize.width;",
|
||||
" }",
|
||||
" if (requestedH == 0) {",
|
||||
" requestedH = _surfaceSize.height;",
|
||||
" }",
|
||||
""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new string[] { line };
|
||||
});
|
||||
}
|
||||
|
||||
private static void EditCodeFile(string path, Func<string, IEnumerable<string>> lineHandler)
|
||||
{
|
||||
var bakPath = path + ".bak";
|
||||
if (File.Exists(bakPath))
|
||||
{
|
||||
File.Delete(bakPath);
|
||||
}
|
||||
|
||||
File.Move(path, bakPath);
|
||||
|
||||
using (var reader = File.OpenText(bakPath))
|
||||
using (var stream = File.Create(path))
|
||||
using (var writer = new StreamWriter(stream))
|
||||
{
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
var outputs = lineHandler(line);
|
||||
foreach (var o in outputs)
|
||||
{
|
||||
writer.WriteLine(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Binary file not shown.
After Width: | Height: | Size: 170 KiB |
Reference in New Issue