diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e53fcf..5f4528e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.4] - 2022-03-14 + +### Changed + +- `/lib/src/model_viewer_plus_mobile.dart`, update according to the [newest document](https://developers.google.com/ar/develop/scene-viewer#3d-or-ar). Fix [#9](https://github.com/omchiii/model_viewer_plus.dart/issues/9). + - Insted of `com.google.ar.core`, now we use `com.google.android.googlequicksearchbox`. This should support the widest possible range of devices. + - Mode defaults to `ar_preferred`. Scene Viewer launches in AR native mode as the entry mode. If Google Play Services for AR isn't present, Scene Viewer gracefully falls back to 3D mode as the entry mode. +- Add `arModes` to example, closer to [modelviewer.dev](https://modelviewer.dev)'s offical example. +- Update `example\android\app\build.gradle` `compileSdkVersion` to 31 +- Update `android_intent_plus` to `3.1.1` +- Update `android_intent_plus to` `3.0.1` + +### Removed + +- `/lib/src/http_proxy.dart`: empty file + ## [1.1.3] - 2022-03-14 ### Changed diff --git a/README.md b/README.md index aa81494..e8fa83e 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,17 @@ web component in a [WebView](https://pub.dev/packages/webview_flutter). Android, iOS, Web, with [a recent system browser version](https://modelviewer.dev/#section-browser-support). +## Notes + +We use the [Google APP](https://play.google.com/store/apps/details?id=com.google.android.googlequicksearchbox), `com.google.android.googlequicksearchbox` to display interactive 3D models on Android. The model displays in 'ar_preferred' mode by default, Scene Viewer launches in AR native mode as the entry mode. If [Google Play Services for AR (ARCore, `com.google.ar.core`)](https://play.google.com/store/apps/details?id=com.google.ar.core) isn't present, Scene Viewer gracefully falls back to 3D mode as the entry mode. + ## Installation ### `pubspec.yaml` ```yaml dependencies: - model_viewer_plus: ^1.0.0 + model_viewer_plus: ^(newest from https://pub.dev/packages/model_viewer_plus) ``` ### `AndroidManifest.xml` (Android 9+ only) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 4ff21f7..80a4b4c 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion 31 lintOptions { disable 'InvalidPackage' diff --git a/example/lib/main.dart b/example/lib/main.dart index f6894ed..6042ac8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,10 +13,11 @@ class MyApp extends StatelessWidget { appBar: AppBar(title: Text("Model Viewer")), body: ModelViewer( backgroundColor: Color.fromARGB(0xFF, 0xEE, 0xEE, 0xEE), - //src: 'https://modelviewer.dev/shared-assets/models/Astronaut.glb', + // src: 'https://modelviewer.dev/shared-assets/models/Astronaut.glb', src: 'assets/Astronaut.glb', // a bundled asset file alt: "A 3D model of an astronaut", ar: true, + arModes: ['scene-viewer', 'webxr', 'quick-look'], autoRotate: true, cameraControls: true, ), diff --git a/lib/.gitkeep b/lib/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/lib/src/html_builder.dart b/lib/src/html_builder.dart index 0115db9..e3e5eac 100644 --- a/lib/src/html_builder.dart +++ b/lib/src/html_builder.dart @@ -75,6 +75,9 @@ abstract class HTMLBuilder { // TODO: shadow-intensity // TODO: shadow-softness html.writeln('>'); + + // print(html.toString()); // DEBUG + return html.toString(); } } diff --git a/lib/src/http_proxy.dart b/lib/src/http_proxy.dart deleted file mode 100644 index 3e7de75..0000000 --- a/lib/src/http_proxy.dart +++ /dev/null @@ -1 +0,0 @@ -/* This is free and unencumbered software released into the public domain. */ diff --git a/lib/src/model_viewer_plus_mobile.dart b/lib/src/model_viewer_plus_mobile.dart index 9b55511..96ac865 100644 --- a/lib/src/model_viewer_plus_mobile.dart +++ b/lib/src/model_viewer_plus_mobile.dart @@ -5,6 +5,7 @@ import 'dart:convert' show utf8; import 'dart:io' show File, HttpRequest, HttpServer, HttpStatus, InternetAddress, Platform; import 'dart:typed_data' show Uint8List; +import 'package:path/path.dart' as p; import 'package:android_intent_plus/flag.dart'; import 'package:flutter/material.dart'; @@ -21,6 +22,7 @@ class ModelViewerState extends State { Completer(); HttpServer? _proxy; + late String _proxyURL; @override void initState() { @@ -59,14 +61,11 @@ class ModelViewerState extends State { initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, onWebViewCreated: (final WebViewController webViewController) async { _controller.complete(webViewController); - final host = _proxy!.address.address; - final port = _proxy!.port; - final url = "http://$host:$port/"; - print('>>>> ModelViewer initializing... <$url>'); // DEBUG - await webViewController.loadUrl(url); + print('>>>> ModelViewer initializing... <$_proxyURL>'); // DEBUG + await webViewController.loadUrl(_proxyURL); }, navigationDelegate: (final NavigationRequest navigation) async { - //print('>>>> ModelViewer wants to load: <${navigation.url}>'); // DEBUG + print('>>>> ModelViewer wants to load: <${navigation.url}>'); // DEBUG if (!Platform.isAndroid) { return NavigationDecision.navigate; } @@ -74,20 +73,53 @@ class ModelViewerState extends State { return NavigationDecision.navigate; } try { + // Original, just keep as a backup // See: https://developers.google.com/ar/develop/java/scene-viewer + // final intent = android_content.AndroidIntent( + // action: "android.intent.action.VIEW", // Intent.ACTION_VIEW + // data: "https://arvr.google.com/scene-viewer/1.0", + // arguments: { + // 'file': widget.src, + // 'mode': 'ar_preferred', + // }, + // package: "com.google.ar.core", + // flags: [ + // Flag.FLAG_ACTIVITY_NEW_TASK + // ], // Intent.FLAG_ACTIVITY_NEW_TASK, + // ); + + // 2022-03-14 update + final String fileURL; + if (['http', 'https'].contains(Uri.parse(widget.src).scheme)) { + fileURL = widget.src; + } else { + fileURL = p.joinAll([_proxyURL, 'model']); + } final intent = android_content.AndroidIntent( action: "android.intent.action.VIEW", // Intent.ACTION_VIEW - data: "https://arvr.google.com/scene-viewer/1.0", + // See https://developers.google.com/ar/develop/scene-viewer#3d-or-ar + // data should be something like "https://arvr.google.com/scene-viewer/1.0?file=https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Avocado/glTF/Avocado.gltf" + data: Uri( + scheme: 'https', + host: 'arvr.google.com', + path: '/scene-viewer/1.0', + queryParameters: { + // 'title': '', // TODO: maybe set by the user + // TODO: further test, and make it 'ar_preferred' + 'mode': 'ar_preferred', + 'file': fileURL, + }).toString(), + // package changed to com.google.android.googlequicksearchbox + // to support the widest possible range of devices + package: "com.google.android.googlequicksearchbox", arguments: { - 'file': widget.src, - 'mode': 'ar_only', + 'browser_fallback_url': + 'market://details?id=com.google.android.googlequicksearchbox' }, - package: "com.google.ar.core", - flags: [ - Flag.FLAG_ACTIVITY_NEW_TASK - ], // Intent.FLAG_ACTIVITY_NEW_TASK, ); - await intent.launch(); + await intent.launch().onError((error, stackTrace) { + print('>>>> ModelViewer Intent Error: $error'); // DEBUG + }); } catch (error) { print('>>>> ModelViewer failed to launch AR: $error'); // DEBUG } @@ -130,6 +162,9 @@ class ModelViewerState extends State { setState(() { _proxy; + final host = _proxy!.address.address; + final port = _proxy!.port; + _proxyURL = "http://$host:$port/"; }); _proxy!.listen((final HttpRequest request) async { diff --git a/lib/src/model_viewer_plus_web.dart b/lib/src/model_viewer_plus_web.dart index 13552d7..9a6f7aa 100644 --- a/lib/src/model_viewer_plus_web.dart +++ b/lib/src/model_viewer_plus_web.dart @@ -5,10 +5,8 @@ import 'package:flutter/services.dart' show rootBundle; import 'html_builder.dart'; -// import 'dart:ui' as ui; import 'shim/dart_ui_fake.dart' if (dart.library.html) 'dart:ui' as ui; import 'shim/dart_html_fake.dart' if (dart.library.html) 'dart:html'; -// import 'dart:html'; import 'model_viewer_plus.dart'; @@ -40,7 +38,6 @@ class ModelViewerState extends State { 'src', 'alt', 'poster', - 'poster', 'seamless-poster', 'loading', 'reveal', diff --git a/pubspec.yaml b/pubspec.yaml index 3778a76..adff4b2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ # See: https://dart.dev/tools/pub/pubspec name: model_viewer_plus -version: 1.1.3 +version: 1.1.4 description: >- A Flutter widget for rendering interactive 3D models in the glTF and GLB formats. @@ -14,8 +14,8 @@ platforms: dependencies: flutter: sdk: flutter - android_intent_plus: ^3.0.2 - webview_flutter: ^3.0.0 + android_intent_plus: ^3.1.1 + webview_flutter: ^3.0.1 dev_dependencies: flutter_test: sdk: flutter