5
5
#import < SafariServices/SafariServices.h>
6
6
7
7
#import " FLTURLLauncherPlugin.h"
8
+ #import " FLTURLLauncherPlugin_Test.h"
9
+ #import " FULLauncher.h"
10
+ #import " messages.g.h"
11
+
12
+ typedef void (^OpenInSafariVCResponse)(NSNumber *_Nullable, FlutterError *_Nullable);
8
13
9
14
@interface FLTURLLaunchSession : NSObject <SFSafariViewControllerDelegate>
10
15
11
- @property (copy , nonatomic ) FlutterResult flutterResult ;
16
+ @property (copy , nonatomic ) OpenInSafariVCResponse completion ;
12
17
@property (strong , nonatomic ) NSURL *url;
13
18
@property (strong , nonatomic ) SFSafariViewController *safari;
14
19
@property (nonatomic , copy ) void (^didFinish)(void );
@@ -17,11 +22,11 @@ @interface FLTURLLaunchSession : NSObject <SFSafariViewControllerDelegate>
17
22
18
23
@implementation FLTURLLaunchSession
19
24
20
- - (instancetype )initWithUrl :url withFlutterResult :result {
25
+ - (instancetype )initWithURL :url completion :completion {
21
26
self = [super init ];
22
27
if (self) {
23
28
self.url = url;
24
- self.flutterResult = result ;
29
+ self.completion = completion ;
25
30
self.safari = [[SFSafariViewController alloc ] initWithURL: url];
26
31
self.safari .delegate = self;
27
32
}
@@ -31,12 +36,13 @@ - (instancetype)initWithUrl:url withFlutterResult:result {
31
36
- (void )safariViewController : (SFSafariViewController *)controller
32
37
didCompleteInitialLoad : (BOOL )didLoadSuccessfully {
33
38
if (didLoadSuccessfully) {
34
- self.flutterResult (@YES );
39
+ self.completion (@YES , nil );
35
40
} else {
36
- self.flutterResult ([FlutterError
37
- errorWithCode: @" Error"
38
- message: [NSString stringWithFormat: @" Error while launching %@ " , self .url]
39
- details: nil ]);
41
+ self.completion (
42
+ nil , [FlutterError
43
+ errorWithCode: @" Error"
44
+ message: [NSString stringWithFormat: @" Error while launching %@ " , self .url]
45
+ details: nil ]);
40
46
}
41
47
}
42
48
@@ -51,64 +57,86 @@ - (void)close {
51
57
52
58
@end
53
59
60
+ #pragma mark -
61
+
62
+ // / Default implementation of FULLancher, using UIApplication.
63
+ @interface FULUIApplicationLauncher : NSObject <FULLauncher>
64
+ @end
65
+
66
+ @implementation FULUIApplicationLauncher
67
+ - (BOOL )canOpenURL : (nonnull NSURL *)url {
68
+ return [[UIApplication sharedApplication ] canOpenURL: url];
69
+ }
70
+
71
+ - (void )openURL : (nonnull NSURL *)url
72
+ options : (nonnull NSDictionary <UIApplicationOpenExternalURLOptionsKey, id> *)options
73
+ completionHandler : (void (^_Nullable)(BOOL ))completion {
74
+ [[UIApplication sharedApplication ] openURL: url options: options completionHandler: completion];
75
+ }
76
+
77
+ @end
78
+
79
+ #pragma mark -
80
+
54
81
@interface FLTURLLauncherPlugin ()
55
82
56
83
@property (strong , nonatomic ) FLTURLLaunchSession *currentSession;
84
+ @property (strong , nonatomic ) NSObject <FULLauncher> *launcher;
57
85
58
86
@end
59
87
60
88
@implementation FLTURLLauncherPlugin
61
89
62
90
+ (void )registerWithRegistrar : (NSObject <FlutterPluginRegistrar> *)registrar {
63
- FlutterMethodChannel *channel =
64
- [FlutterMethodChannel methodChannelWithName: @" plugins.flutter.io/url_launcher_ios"
65
- binaryMessenger: registrar.messenger];
66
91
FLTURLLauncherPlugin *plugin = [[FLTURLLauncherPlugin alloc ] init ];
67
- [registrar addMethodCallDelegate: plugin channel: channel];
68
- }
69
-
70
- - (void )handleMethodCall : (FlutterMethodCall *)call result : (FlutterResult)result {
71
- NSString *url = call.arguments [@" url" ];
72
- if ([@" canLaunch" isEqualToString: call.method]) {
73
- result (@([self canLaunchURL: url]));
74
- } else if ([@" launch" isEqualToString: call.method]) {
75
- NSNumber *useSafariVC = call.arguments [@" useSafariVC" ];
76
- if (useSafariVC.boolValue ) {
77
- [self launchURLInVC: url result: result];
78
- } else {
79
- [self launchURL: url call: call result: result];
80
- }
81
- } else if ([@" closeWebView" isEqualToString: call.method]) {
82
- [self closeWebViewWithResult: result];
83
- } else {
84
- result (FlutterMethodNotImplemented);
92
+ FULUrlLauncherApiSetup (registrar.messenger , plugin);
93
+ }
94
+
95
+ - (instancetype )init {
96
+ return [self initWithLauncher: [[FULUIApplicationLauncher alloc ] init ]];
97
+ }
98
+
99
+ - (instancetype )initWithLauncher : (NSObject <FULLauncher> *)launcher {
100
+ if (self = [super init ]) {
101
+ _launcher = launcher;
85
102
}
103
+ return self;
86
104
}
87
105
88
- - (BOOL )canLaunchURL : (NSString *)urlString {
106
+ - (nullable NSNumber *)canLaunchURL : (NSString *)urlString
107
+ error : (FlutterError *_Nullable *_Nonnull)error {
89
108
NSURL *url = [NSURL URLWithString: urlString];
90
- UIApplication *application = [UIApplication sharedApplication ];
91
- return [application canOpenURL: url];
109
+ if (!url) {
110
+ *error = [self invalidURLErrorForURLString: urlString];
111
+ return nil ;
112
+ }
113
+ return @([self .launcher canOpenURL: url]);
92
114
}
93
115
94
116
- (void )launchURL : (NSString *)urlString
95
- call : (FlutterMethodCall *)call
96
- result : (FlutterResult) result {
117
+ universalLinksOnly : ( NSNumber *)universalLinksOnly
118
+ completion : ( void (^)( NSNumber *_Nullable, FlutterError *_Nullable)) completion {
97
119
NSURL *url = [NSURL URLWithString: urlString];
98
- UIApplication *application = [UIApplication sharedApplication ];
99
-
100
- NSNumber *universalLinksOnly = call.arguments [@" universalLinksOnly" ] ?: @0 ;
120
+ if (!url) {
121
+ completion (nil , [self invalidURLErrorForURLString: urlString]);
122
+ return ;
123
+ }
101
124
NSDictionary *options = @{UIApplicationOpenURLOptionUniversalLinksOnly : universalLinksOnly};
102
- [application openURL: url
103
- options: options
104
- completionHandler: ^(BOOL success) {
105
- result (@(success));
106
- }];
125
+ [self .launcher openURL: url
126
+ options: options
127
+ completionHandler: ^(BOOL success) {
128
+ completion (@(success), nil );
129
+ }];
107
130
}
108
131
109
- - (void )launchURLInVC : (NSString *)urlString result : (FlutterResult)result {
132
+ - (void )openSafariViewControllerWithURL : (NSString *)urlString
133
+ completion : (OpenInSafariVCResponse)completion {
110
134
NSURL *url = [NSURL URLWithString: urlString];
111
- self.currentSession = [[FLTURLLaunchSession alloc ] initWithUrl: url withFlutterResult: result];
135
+ if (!url) {
136
+ completion (nil , [self invalidURLErrorForURLString: urlString]);
137
+ return ;
138
+ }
139
+ self.currentSession = [[FLTURLLaunchSession alloc ] initWithURL: url completion: completion];
112
140
__weak typeof (self) weakSelf = self;
113
141
self.currentSession .didFinish = ^(void ) {
114
142
weakSelf.currentSession = nil ;
@@ -118,11 +146,8 @@ - (void)launchURLInVC:(NSString *)urlString result:(FlutterResult)result {
118
146
completion: nil ];
119
147
}
120
148
121
- - (void )closeWebViewWithResult : (FlutterResult)result {
122
- if (self.currentSession != nil ) {
123
- [self .currentSession close ];
124
- }
125
- result (nil );
149
+ - (void )closeSafariViewControllerWithError : (FlutterError *_Nullable *_Nonnull)error {
150
+ [self .currentSession close ];
126
151
}
127
152
128
153
- (UIViewController *)topViewController {
@@ -162,4 +187,16 @@ - (UIViewController *)topViewControllerFromViewController:(UIViewController *)vi
162
187
}
163
188
return viewController;
164
189
}
190
+
191
+ /* *
192
+ * Creates an error for an invalid URL string.
193
+ *
194
+ * @param url The invalid URL string
195
+ * @return The error to return
196
+ */
197
+ - (FlutterError *)invalidURLErrorForURLString : (NSString *)url {
198
+ return [FlutterError errorWithCode: @" argument_error"
199
+ message: @" Unable to parse URL"
200
+ details: [NSString stringWithFormat: @" Provided URL: %@ " , url]];
201
+ }
165
202
@end
0 commit comments