반응형
프로젝트 진행중 웹에서 confirm() 함수를 호출하는 데 webview_flutter 3.0.4기준으로 안드로이드는 정상적으로 시스템 confirm창이 노출이 되는데 아이폰에서는 노출이 되지 않는 현상이 발생했습니다.
그래서 구글링 한 결과 webview_flutter 소스에서 기본적으로 지원을 하지 않고 직접 소스를 수정해서 적용하면 가능하다는 블로그를 보고 적용해봤습니다.
※ 경로(Mac 기준)
- 2.0.3 기준 경로 :
/Users/${사용자}/Dev/SDKs/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter-2.0.13/ios/Classes/FlutterWebView.m
- 3.0.4 기준 경로 :
/Users/${사용자}/Dev/SDKs/flutter/.pub-cache/hosted/pub.dartlang.org/webview_flutter_wkwebview-2.9.2/ios/Classes/FWFUIDelegateHostApi.m
※ 적용할 소스
@implementation FWFUIDelegate
//...
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"알림" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"확인" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler();
}]];
UIViewController *_viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[_viewController presentViewController:alertController animated:YES completion:nil];
}
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"알림" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"예" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
completionHandler(YES);
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"아니오" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler(NO);
}]];
UIViewController *_viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[_viewController presentViewController:alertController animated:YES completion:nil];
}
@end
※ 헷갈리실 분들을 위해 전문 첨부 합니다
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "FWFUIDelegateHostApi.h"
#import "FWFDataConverters.h"
@interface FWFUIDelegateFlutterApiImpl ()
// BinaryMessenger must be weak to prevent a circular reference with the host API it
// references.
@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
// InstanceManager must be weak to prevent a circular reference with the object it stores.
@property(nonatomic, weak) FWFInstanceManager *instanceManager;
@end
@implementation FWFUIDelegateFlutterApiImpl
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
instanceManager:(FWFInstanceManager *)instanceManager {
self = [self initWithBinaryMessenger:binaryMessenger];
if (self) {
_binaryMessenger = binaryMessenger;
_instanceManager = instanceManager;
_webViewConfigurationFlutterApi =
[[FWFWebViewConfigurationFlutterApiImpl alloc] initWithBinaryMessenger:binaryMessenger
instanceManager:instanceManager];
}
return self;
}
- (long)identifierForDelegate:(FWFUIDelegate *)instance {
return [self.instanceManager identifierWithStrongReferenceForInstance:instance];
}
- (void)onCreateWebViewForDelegate:(FWFUIDelegate *)instance
webView:(WKWebView *)webView
configuration:(WKWebViewConfiguration *)configuration
navigationAction:(WKNavigationAction *)navigationAction
completion:(void (^)(NSError *_Nullable))completion {
if (![self.instanceManager containsInstance:configuration]) {
[self.webViewConfigurationFlutterApi createWithConfiguration:configuration
completion:^(NSError *error) {
NSAssert(!error, @"%@", error);
}];
}
NSNumber *configurationIdentifier =
@([self.instanceManager identifierWithStrongReferenceForInstance:configuration]);
FWFWKNavigationActionData *navigationActionData =
FWFWKNavigationActionDataFromNavigationAction(navigationAction);
[self onCreateWebViewForDelegateWithIdentifier:@([self identifierForDelegate:instance])
webViewIdentifier:
@([self.instanceManager
identifierWithStrongReferenceForInstance:webView])
configurationIdentifier:configurationIdentifier
navigationAction:navigationActionData
completion:completion];
}
@end
@implementation FWFUIDelegate
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
instanceManager:(FWFInstanceManager *)instanceManager {
self = [super initWithBinaryMessenger:binaryMessenger instanceManager:instanceManager];
if (self) {
_UIDelegateAPI = [[FWFUIDelegateFlutterApiImpl alloc] initWithBinaryMessenger:binaryMessenger
instanceManager:instanceManager];
}
return self;
}
- (WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction
windowFeatures:(WKWindowFeatures *)windowFeatures {
[self.UIDelegateAPI onCreateWebViewForDelegate:self
webView:webView
configuration:configuration
navigationAction:navigationAction
completion:^(NSError *error) {
NSAssert(!error, @"%@", error);
}];
return nil;
}
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"확인" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler();
}]];
UIViewController *_viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[_viewController presentViewController:alertController animated:YES completion:nil];
}
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"예" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
completionHandler(YES);
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"아니오" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler(NO);
}]];
UIViewController *_viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[_viewController presentViewController:alertController animated:YES completion:nil];
}
@end
@interface FWFUIDelegateHostApiImpl ()
// BinaryMessenger must be weak to prevent a circular reference with the host API it
// references.
@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
// InstanceManager must be weak to prevent a circular reference with the object it stores.
@property(nonatomic, weak) FWFInstanceManager *instanceManager;
@end
@implementation FWFUIDelegateHostApiImpl
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
instanceManager:(FWFInstanceManager *)instanceManager {
self = [self init];
if (self) {
_binaryMessenger = binaryMessenger;
_instanceManager = instanceManager;
}
return self;
}
- (FWFUIDelegate *)delegateForIdentifier:(NSNumber *)identifier {
return (FWFUIDelegate *)[self.instanceManager instanceForIdentifier:identifier.longValue];
}
- (void)createWithIdentifier:(nonnull NSNumber *)identifier
error:(FlutterError *_Nullable *_Nonnull)error {
FWFUIDelegate *uIDelegate = [[FWFUIDelegate alloc] initWithBinaryMessenger:self.binaryMessenger
instanceManager:self.instanceManager];
[self.instanceManager addDartCreatedInstance:uIDelegate withIdentifier:identifier.longValue];
}
@end