1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'types.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;
MethodChannel _channel;
static const MethodChannel _sharedChannel = const MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser');
///Initialize the [ChromeSafariBrowser] instance with an [InAppBrowser] fallback instance or `null`.
ChromeSafariBrowser({bFallback}) {
uuid = uuidGenerator.v4();
browserFallback = bFallback;
this._channel =
MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser_$uuid');
this._channel.setMethodCallHandler(handleMethod);
_isOpened = false;
}
Future<dynamic> handleMethod(MethodCall call) async {
switch (call.method) {
case "onChromeSafariBrowserOpened":
onOpened();
break;
case "onChromeSafariBrowserCompletedInitialLoad":
onCompletedInitialLoad();
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<void> open(
{@required String url,
ChromeSafariBrowserClassOptions options,
Map<String, String> headersFallback = const {},
InAppBrowserClassOptions optionsFallback}) async {
assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!');
Map<String, dynamic> optionsMap = {};
if (Platform.isAndroid)
optionsMap.addAll(options.android?.toMap() ?? {});
else if (Platform.isIOS)
optionsMap.addAll(options.ios?.toMap() ?? {});
Map<String, dynamic> 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<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => url);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('headersFallback', () => headersFallback);
args.putIfAbsent('optionsFallback', () => optionsFallbackMap);
await _sharedChannel.invokeMethod('open', args);
this._isOpened = true;
}
///Event fires when the [ChromeSafariBrowser] is opened.
void onOpened() {}
///Event fires when the initial URL load is complete.
void onCompletedInitialLoad() {}
///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.'
]);
}
}
}