Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android textureview player #1

Merged
merged 15 commits into from
Aug 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ example/unity/DemoApp/Temp/
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/unitypackages/flutter_tools/test/data/dart_dependencies_test/**/.packages

example/unity/DemoApp/test
example/ios/UnityLibrary
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 4.2.1

* Improved nullsafety

## 4.2.0

* Null safe merged to master

## 4.1.0-null-safe

* Fixed bitcode enabled issue on iOS. [369](https://github.com/juicycleff/flutter-unity-view-widget/issues/369)

## 4.1.0

* Fixed bitcode enabled issue on iOS. [369](https://github.com/juicycleff/flutter-unity-view-widget/issues/369)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Null-safe version:

```yaml
dependencies:
flutter_unity_widget: ^4.1.0-null-safe
flutter_unity_widget: ^4.2.1
```

Now inside your Dart code you can import it.
Expand Down
3 changes: 3 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
analyzer:
enable-experiment:
- non-nullable
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package com.xraph.plugin.flutter_unity_widget

import android.app.Activity
import android.graphics.PixelFormat
import android.graphics.SurfaceTexture
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.WindowManager
import android.view.Surface
import android.view.TextureView
import com.unity3d.player.IUnityPlayerLifecycleEvents
import com.unity3d.player.UnityPlayer
import java.util.concurrent.CopyOnWriteArraySet
Expand Down Expand Up @@ -43,6 +46,27 @@ class UnityPlayerUtils {
if (!reInitialize) {
activity.window.setFormat(PixelFormat.RGBA_8888)
unityPlayer = UnityPlayer(activity, ule)

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand any of this lol. Which is fine. Just one question out of curiosity. This if seems to be checking if the version number is below zero? Wondering what this is checking.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build.VERSION_CODES.O at first glance does look like a 0. I wish they didn't truncate "Oreo" to "O". At runtime this constant int is 26. https://developer.android.com/reference/android/os/Build.VERSION_CODES#O

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding what the code does, the majority of the work is happening within the unity generated library via unityPlayer!!.addViewToPlayer(view, true). The code above that is instantiating a TextureView from the Android SDK and setting it up so that the unity player view renders to it. The unity player shows our newly made TextureView because calling addViewToPlayer swaps the internal surface with our TextureView.

val view = TextureView(activity)
view.isOpaque = false
view.surfaceTextureListener = object: TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
unityPlayer!!.displayChanged(0, Surface(surface))
}

override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
return true
}

override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture , width: Int, height: Int) {
}

override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
}
}
unityPlayer!!.addViewToPlayer(view, true)
}
}

try {
Expand Down
84 changes: 41 additions & 43 deletions lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,18 @@ part of flutter_unity_widget;

typedef void UnityCreatedCallback(UnityWidgetController controller);

final UnityViewFlutterPlatform _unityViewFlutterPlatform =
UnityViewFlutterPlatform.instance;

class UnityWidgetController {
final _UnityWidgetState _unityWidgetState;

/// The unityId for this controller
final int unityId;

/// used for cancel the subscription
StreamSubscription _onUnityMessageSub,
StreamSubscription? _onUnityMessageSub,
_onUnitySceneLoadedSub,
_onUnityUnloadedSub;

UnityWidgetController._(this._unityWidgetState, {@required this.unityId})
: assert(_unityViewFlutterPlatform != null) {
UnityWidgetController._(this._unityWidgetState, {required this.unityId}) {
_connectStreams(unityId);
}

Expand All @@ -26,87 +22,88 @@ class UnityWidgetController {
/// in [UnityWidget.onUnityCreated] callback.
static Future<UnityWidgetController> init(
int id, _UnityWidgetState unityWidgetState) async {
assert(id != null);
await _unityViewFlutterPlatform.init(id);
await UnityViewFlutterPlatform.instance.init(id);
return UnityWidgetController._(
unityWidgetState,
unityId: id,
);
}

@visibleForTesting
MethodChannel get channel {
if (_unityViewFlutterPlatform is MethodChannelUnityViewFlutter) {
return (_unityViewFlutterPlatform as MethodChannelUnityViewFlutter)
MethodChannel? get channel {
if (UnityViewFlutterPlatform.instance is MethodChannelUnityViewFlutter) {
return (UnityViewFlutterPlatform.instance
as MethodChannelUnityViewFlutter)
.channel(unityId);
}
return null;
}

void _connectStreams(int unityId) {
if (_unityWidgetState.widget.onUnityMessage != null) {
_onUnityMessageSub = _unityViewFlutterPlatform
_onUnityMessageSub = UnityViewFlutterPlatform.instance
.onUnityMessage(unityId: unityId)
.listen((UnityMessageEvent e) =>
_unityWidgetState.widget.onUnityMessage(e.value));
_unityWidgetState.widget.onUnityMessage!(e.value));
}

if (_unityWidgetState.widget.onUnitySceneLoaded != null) {
_onUnitySceneLoadedSub = _unityViewFlutterPlatform
_onUnitySceneLoadedSub = UnityViewFlutterPlatform.instance
.onUnitySceneLoaded(unityId: unityId)
.listen((UnitySceneLoadedEvent e) =>
_unityWidgetState.widget.onUnitySceneLoaded(e.value));
_unityWidgetState.widget.onUnitySceneLoaded!(e.value));
}

if (_unityWidgetState.widget.onUnityUnloaded != null) {
_onUnityUnloadedSub = _unityViewFlutterPlatform
_onUnityUnloadedSub = UnityViewFlutterPlatform.instance
.onUnityUnloaded(unityId: unityId)
.listen((_) => _unityWidgetState.widget.onUnityUnloaded());
.listen((_) => _unityWidgetState.widget.onUnityUnloaded!());
}
}

/// Checks to see if unity player is ready to be used
/// Returns `true` if unity player is ready.
Future<bool> isReady() {
Future<bool?>? isReady() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.isReady(unityId: unityId);
return UnityViewFlutterPlatform.instance.isReady(unityId: unityId);
}
return null;
}

/// Get the current pause state of the unity player
/// Returns `true` if unity player is paused.
Future<bool> isPaused() {
Future<bool?>? isPaused() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.isPaused(unityId: unityId);
return UnityViewFlutterPlatform.instance.isPaused(unityId: unityId);
}
return null;
}

/// Get the current load state of the unity player
/// Returns `true` if unity player is loaded.
Future<bool> isLoaded() {
Future<bool?>? isLoaded() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.isLoaded(unityId: unityId);
return UnityViewFlutterPlatform.instance.isLoaded(unityId: unityId);
}
return null;
}

/// Helper method to know if Unity has been put in background mode (WIP) unstable
/// Returns `true` if unity player is in background.
Future<bool> inBackground() {
Future<bool?>? inBackground() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.inBackground(unityId: unityId);
return UnityViewFlutterPlatform.instance.inBackground(unityId: unityId);
}
return null;
}

/// Creates a unity player if it's not already created. Please only call this if unity is not ready,
/// or is in unloaded state. Use [isLoaded] to check.
/// Returns `true` if unity player was created succesfully.
Future<bool> create() {
Future<bool?>? create() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.createUnityPlayer(unityId: unityId);
return UnityViewFlutterPlatform.instance
.createUnityPlayer(unityId: unityId);
}
return null;
}
Expand All @@ -118,9 +115,9 @@ class UnityWidgetController {
/// ```dart
/// postMessage("GameManager", "openScene", "ThirdScene")
/// ```
Future<void> postMessage(String gameObject, methodName, message) {
Future<void>? postMessage(String gameObject, methodName, message) {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.postMessage(
return UnityViewFlutterPlatform.instance.postMessage(
unityId: unityId,
gameObject: gameObject,
methodName: methodName,
Expand All @@ -137,10 +134,10 @@ class UnityWidgetController {
/// ```dart
/// postJsonMessage("GameManager", "openScene", {"buildIndex": 3, "name": "ThirdScene"})
/// ```
Future<void> postJsonMessage(
Future<void>? postJsonMessage(
String gameObject, String methodName, Map<String, dynamic> message) {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.postJsonMessage(
return UnityViewFlutterPlatform.instance.postJsonMessage(
unityId: unityId,
gameObject: gameObject,
methodName: methodName,
Expand All @@ -151,43 +148,44 @@ class UnityWidgetController {
}

/// Pause the unity in-game player with this method
Future<void> pause() {
Future<void>? pause() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.pausePlayer(unityId: unityId);
return UnityViewFlutterPlatform.instance.pausePlayer(unityId: unityId);
}
return null;
}

/// Resume the unity in-game player with this method idf it is in a paused state
Future<void> resume() {
Future<void>? resume() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.resumePlayer(unityId: unityId);
return UnityViewFlutterPlatform.instance.resumePlayer(unityId: unityId);
}
return null;
}

/// Sometimes you want to open unity in it's own process and openInNativeProcess does just that.
/// It works for Android and iOS is WIP
Future<void> openInNativeProcess() {
Future<void>? openInNativeProcess() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.openInNativeProcess(unityId: unityId);
return UnityViewFlutterPlatform.instance
.openInNativeProcess(unityId: unityId);
}
return null;
}

/// Unloads unity player from th current process (Works on Android only for now)
/// iOS is WIP. For more information please read [Unity Docs](https://docs.unity3d.com/2020.2/Documentation/Manual/UnityasaLibrary.html)
Future<void> unload() {
Future<void>? unload() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.unloadPlayer(unityId: unityId);
return UnityViewFlutterPlatform.instance.unloadPlayer(unityId: unityId);
}
return null;
}

/// Quits unity player. Note that this kills the current flutter process, thus quiting the app
Future<void> quit() {
Future<void>? quit() {
if (!_unityWidgetState.widget.enablePlaceholder) {
return _unityViewFlutterPlatform.quitPlayer(unityId: unityId);
return UnityViewFlutterPlatform.instance.quitPlayer(unityId: unityId);
}
return null;
}
Expand All @@ -205,12 +203,12 @@ class UnityWidgetController {

void dispose() {
_cancelSubscriptions();
_unityViewFlutterPlatform.dispose(unityId: unityId);
UnityViewFlutterPlatform.instance.dispose(unityId: unityId);
}
}

typedef void UnityMessageCallback(dynamic handler);

typedef void UnitySceneChangeCallback(SceneLoaded message);
typedef void UnitySceneChangeCallback(SceneLoaded? message);

typedef void UnityUnloadCallback();
Loading