This repository is used to demonstrate how the AR-MOD SDK can be used in Flutter.
- 
Install this plugin to your flutter project. If you do not know how to install the
Flutter Packageyou can click here to see the document.Install Guid
The AR-MOD SDK currently provides a plug-in package for Flutter. You can install it through
flutter_armod_widget: ^0.0.3in your flutter projectpubspec.yaml!# Other config dependencies: flutter: sdk: flutter flutter_armod_widget: ^0.0.3 # Other config
 - 
Go to PhantomsXR github respository. Download and Unzip it.
 - 
Choose iOS or Android platform from the options below to set.
Android Setup
- 
Go to the location of your
FLUTTER SDK PATH/.pub-cache/hosted/pub.dartlang.org/flutter_armod_widget-0.0.3/folder, then paste thelibstoandroidplatform folder. - 
Run
Flutter pub getcommand in your termial. 
iOS Setup
- 
Create the
ThirdPartiesfolder to your XCode project. - 
Import
UnityFramework.frameworkto the folder(ThridParties). - 
Add the Framewrok to Xcode -> Targets -> Your APP -> General -> Franework,Libraries, and Embedded Content area, And set the Embed mode to Embed & Sign.
 - 
Execute the
cd iOScommand and runPod installcommand in your termial. - 
Double-Click to open the
Runner.xcworkspacefile. It will be launch the XCode app. - 
If you're using Swift, open the ios/Runner/AppDelegate.swift file and change the following:
import UIKit import Flutter + import flutter_armod_widget @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + InitARMODIntegrationWithOptions(argc: CommandLine.argc, argv: CommandLine.unsafeArgv, launchOptions) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } }If you're using Objective-C, open the ios/Runner/main.m file and change the following:
+ #import "flutter_armod_widget.swift.h" int main(int argc, char * argv[]) { @autoreleasepool { + InitARMODIntegration(argc, argv); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
 - 
Edit the info.plist
<dict> + <key>io.flutter.embedded_views_preview</key> + <string>YES</string> </dict>
<dict> + <key>Privacy - Camera Usage Description</key> + <string>$(PRODUCT_NAME) uses Cameras</string> </dict>
<dict> + <key>NSBonjourServices</key> + <string>_dartobservatory._tcp</string> </dict>
 
 - 
 - 
Create and write your app token to PhantomsXRConfig.dart.
 - 
And write a new screen for AR-MOD.
 
- 
Q: ios/Flutter/Generated.xcconfig must exist.
- A: Execute 
Flutter runcommand to generate theGenerated.xcconfigfile 
 - A: Execute 
 - 
Q: CocoaPods could not find compatible versions for pod "flutter_armod_widget"
- A: Find and replace the 
platform :ios, '9.0'toplatform :ios, '11.0'in the Podfile. Then ExecutePod updatecommand to refresh your project. 
 - A: Find and replace the 
 
import 'dart:async';
import 'package:armod_flutter_store/src/model/data.dart';
import 'package:armod_flutter_store/src/themes/theme.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_armod_widget/flutter_armod_widget.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import '../config/phantomsxrConfig.dart';
class ARView extends StatefulWidget {
  ARView({Key? key}) : super(key: key);
  @override
  ARViewState createState() => ARViewState();
}
class ARViewState extends State<ARView> {
  late ARMODWidgetController _armodWidgetController;
  bool _onWillPop = false;
  @override
  void initState() {
    super.initState();
  }
  @override
  void dispose() {
    super.dispose();
  }
  Widget _appBar() {
    return SafeArea(
        top: true,
        child: GestureDetector(
          child: Container(
            padding: AppTheme.padding,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Container(
                  width: 25,
                  height: 25,
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.all(Radius.circular(15)),
                  ),
                  child: Icon(Icons.close, color: Colors.black54, size: 20),
                )
              ],
            ),
          ),
          onTap: () async {
            bool willPop = await _onBackPressed();
            if (willPop) Navigator.of(context).pop(true);
          },
        ));
  }
  @override
  Widget build(BuildContext context) {
    return new WillPopScope(
      onWillPop: _onBackPressed,
      child: new Scaffold(
        body: SafeArea(
            top: true,
            child: Stack(
              children: [
                ARMODWidget(
                  onARMODCreated: onARMODCreate,
                  onARMODExit: onARMODExit,
                  onARMODLaunch: onARMODLaunch,
                  onAddLoadingOverlay: onAddLoadingOverlay,
                  onDeviceNotSupport: onDeviceNotSupport,
                  onNeedInstallARCoreService: onNeedInstallARCoreService,
                  onOpenBuiltInBrowser: onOpenBuiltInBrowser,
                  onPackageSizeMoreThanPresetSize:
                      onPackageSizeMoreThanPresetSize,
                  onRecognitionComplete: onRecognitionComplete,
                  onRecognitionStart: onRecognitionStart,
                  onRemoveLoadingOverlay: onRemoveLoadingOverlay,
                  onSdkInitialized: onSdkInitialized,
                  onThrowException: onThrowException,
                  onTryAcquireInformation: onTryAcquireInformation,
                  onUpdateLoadingProgress: onUpdateLoadingProgress,
                  fullscreen: true,
                ),
                _appBar()
              ],
            )),
      ),
    );
  }
  ///Handling the back event
  Future<bool> _onBackPressed() async {
    //Close AR-MOD SDK
    _armodWidgetController.unloadAndHideARMOD();
    while (!_onWillPop) {
      //We need to delayed executed because release AR-MOD operation is async.
      //May need to wait one more frame
      await Future.delayed(Duration(milliseconds: 1));
    }
    return _onWillPop;
  }
  showAlertDialog(BuildContext context, String title, String msg) {
    // set up the button
    Widget okButton = TextButton(
      child: Text("OK"),
      onPressed: () {
        Navigator.of(context).pop();
      },
    );
    // set up the AlertDialog
    AlertDialog alert = AlertDialog(
      title: Text(title),
      content: Text(msg),
      actions: [
        okButton,
      ],
    );
    // show the dialog
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }
  Future<void> onARMODCreate(controller) async {
    this._armodWidgetController = controller;
    if (await _armodWidgetController.isLoaded() != false)
      _armodWidgetController.create();
  }
  void onARMODLaunch() {
    print("----------------------------");
    print("-------onARMODLaunch---------");
    print("----------------------------");
    _armodWidgetController.initARMOD(
        '{"EngineType":"Native","dashboardConfig":{"dashboardGateway":"https://weacw.com/api/v1/getarexperience","token":"${PhantomsXRConfig.AppToken}","timeout":30,"maximumDownloadSize":30},"imageCloudRecognizerConfig":{"gateway":"","maximumOfRetries":5,"frequencyOfScan":5}}');
    Future.delayed(Duration(milliseconds: 125),
        () => {_armodWidgetController.fetchProject(AppData.ar_experience_uid)});
  }
  void onThrowException(String errorMsg, int erorCode) {
    EasyLoading.dismiss();
    showAlertDialog(context, "(Error:$erorCode)", errorMsg);
  }
  void onARMODExit() {
    print("----------------------------");
    print("-------onARMODExit---------");
    print("----------------------------");
    _onWillPop = true;
  }
  void onUpdateLoadingProgress(progress) {
    EasyLoading.showProgress(progress,
        status: '${(progress * 100).toStringAsFixed(0)}%');
  }
  Future<String> onTryAcquireInformation(String opTag) async {
    await Future.delayed(Duration(seconds: 3));
    return "onTryAcquireInformation_$opTag";
  }
  void onAddLoadingOverlay() {
    EasyLoading.instance
      ..indicatorType = EasyLoadingIndicatorType.fadingCircle
      ..maskColor = Colors.red.withOpacity(0.5)
      ..dismissOnTap = false;
  }
  void onRemoveLoadingOverlay() {
    EasyLoading.dismiss();
  }
  void onDeviceNotSupport() {}
  void onRecognitionStart() {}
  void onNeedInstallARCoreService() {}
  void onSdkInitialized() {}
  void onOpenBuiltInBrowser(url) {}
  void onPackageSizeMoreThanPresetSize(currentSize, presetSize) {}
  void onRecognitionComplete() {}
}