import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'types.dart'; import 'channel_manager.dart'; import 'in_app_browser.dart'; ///ChromeSafariBrowser class. /// ///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android ///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS. /// ///[browserFallback] represents the [InAppBrowser] instance fallback in case `Chrome Custom Tabs`/`SFSafariViewController` is not available. class ChromeSafariBrowser { String uuid; InAppBrowser browserFallback; bool _isOpened = false; ///Initialize the [ChromeSafariBrowser] instance with an [InAppBrowser] fallback instance or `null`. ChromeSafariBrowser({bFallback}) { uuid = uuidGenerator.v4(); browserFallback = bFallback; ChannelManager.addListener(uuid, handleMethod); _isOpened = false; } Future handleMethod(MethodCall call) async { switch (call.method) { case "onChromeSafariBrowserOpened": onOpened(); break; case "onChromeSafariBrowserLoaded": onLoaded(); break; case "onChromeSafariBrowserClosed": onClosed(); this._isOpened = false; break; default: throw UnimplementedError("Unimplemented ${call.method} method"); } } ///Opens an [url] in a new [ChromeSafariBrowser] instance. /// ///[url]: The [url] to load. Call [encodeUriComponent()] on this if the [url] contains Unicode characters. /// ///[options]: Options for the [ChromeSafariBrowser]. /// ///[headersFallback]: The additional header of the [InAppBrowser] instance fallback to be used in the HTTP request for this URL, specified as a map from name to value. /// ///[optionsFallback]: Options used by the [InAppBrowser] instance fallback. Future open( {@required String url, ChromeSafariBrowserClassOptions options, Map headersFallback = const {}, InAppBrowserClassOptions optionsFallback}) async { assert(url != null && url.isNotEmpty); this.throwIsAlreadyOpened(message: 'Cannot open $url!'); Map optionsMap = {}; if (Platform.isAndroid) optionsMap.addAll(options.android?.toMap() ?? {}); else if (Platform.isIOS) optionsMap.addAll(options.ios?.toMap() ?? {}); Map optionsFallbackMap = {}; if (optionsFallback != null) { optionsFallbackMap .addAll(optionsFallback.crossPlatform?.toMap() ?? {}); optionsFallbackMap.addAll(optionsFallback .inAppWebViewWidgetOptions?.crossPlatform ?.toMap() ?? {}); if (Platform.isAndroid) { optionsFallbackMap .addAll(optionsFallback.android?.toMap() ?? {}); optionsFallbackMap.addAll(optionsFallback .inAppWebViewWidgetOptions?.android ?.toMap() ?? {}); } else if (Platform.isIOS) { optionsFallbackMap .addAll(optionsFallback.ios?.toMap() ?? {}); optionsFallbackMap.addAll(optionsFallback .inAppWebViewWidgetOptions?.ios ?.toMap() ?? {}); } } Map args = {}; args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuidFallback', () => (browserFallback != null) ? browserFallback.uuid : ''); args.putIfAbsent('url', () => url); args.putIfAbsent('headers', () => headersFallback); args.putIfAbsent('options', () => optionsMap); args.putIfAbsent('optionsFallback', () => optionsFallbackMap); args.putIfAbsent('isData', () => false); args.putIfAbsent('useChromeSafariBrowser', () => true); await ChannelManager.channel.invokeMethod('open', args); this._isOpened = true; } ///Event fires when the [ChromeSafariBrowser] is opened. void onOpened() {} ///Event fires when the [ChromeSafariBrowser] is loaded. void onLoaded() {} ///Event fires when the [ChromeSafariBrowser] is closed. void onClosed() {} ///Returns `true` if the [ChromeSafariBrowser] instance is opened, otherwise `false`. bool isOpened() { return this._isOpened; } void throwIsAlreadyOpened({String message = ''}) { if (this.isOpened()) { throw Exception([ 'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.' ]); } } void throwIsNotOpened({String message = ''}) { if (!this.isOpened()) { throw Exception([ 'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.' ]); } } }