FIRDLJavaScriptExecutor.m 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <WebKit/WebKit.h>
  17. #import "DynamicLinks/FIRDLJavaScriptExecutor.h"
  18. // define below needed because nullability of UIWebViewDelegate method param was changed between
  19. // iOS SDK versions
  20. #if (defined(__IPHONE_10_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0))
  21. #define FIRDL_NULLABLE_IOS9_NONNULLABLE_IOS10 nonnull
  22. #else
  23. #define FIRDL_NULLABLE_IOS9_NONNULLABLE_IOS10 nullable
  24. #endif
  25. NS_ASSUME_NONNULL_BEGIN
  26. static NSString *const kJSMethodName = @"generateFingerprint";
  27. /** Creates and returns the FDL JS method name. */
  28. NSString *FIRDLTypeofFingerprintJSMethodNameString() {
  29. static NSString *methodName;
  30. static dispatch_once_t onceToken;
  31. dispatch_once(&onceToken, ^{
  32. methodName = [NSString stringWithFormat:@"typeof(%@)", kJSMethodName];
  33. });
  34. return methodName;
  35. }
  36. /** Creates and returns the FDL JS method definition. */
  37. NSString *GINFingerprintJSMethodString() {
  38. static NSString *methodString;
  39. static dispatch_once_t onceToken;
  40. dispatch_once(&onceToken, ^{
  41. methodString = [NSString stringWithFormat:@"%@()", kJSMethodName];
  42. });
  43. return methodString;
  44. }
  45. @interface FIRDLJavaScriptExecutor () <UIWebViewDelegate, WKNavigationDelegate>
  46. @end
  47. @implementation FIRDLJavaScriptExecutor {
  48. __weak id<FIRDLJavaScriptExecutorDelegate> _delegate;
  49. NSString *_script;
  50. // Web view with which to run JavaScript.
  51. WKWebView *_wkWebView;
  52. }
  53. - (instancetype)initWithDelegate:(id<FIRDLJavaScriptExecutorDelegate>)delegate
  54. script:(NSString *)script {
  55. NSParameterAssert(delegate);
  56. NSParameterAssert(script);
  57. NSParameterAssert(script.length > 0);
  58. NSAssert([NSThread isMainThread], @"%@ must be used in main thread",
  59. NSStringFromClass([self class]));
  60. if (self = [super init]) {
  61. _delegate = delegate;
  62. _script = [script copy];
  63. [self start];
  64. }
  65. return self;
  66. }
  67. #pragma mark - Internal methods
  68. - (void)start {
  69. NSString *htmlContent =
  70. [NSString stringWithFormat:@"<html><head><script>%@</script></head></html>", _script];
  71. _wkWebView = [[WKWebView alloc] init];
  72. _wkWebView.navigationDelegate = self;
  73. [_wkWebView loadHTMLString:htmlContent baseURL:nil];
  74. }
  75. - (void)handleExecutionResult:(NSString *)result {
  76. [self cleanup];
  77. [_delegate javaScriptExecutor:self completedExecutionWithResult:result];
  78. }
  79. - (void)handleExecutionError:(nullable NSError *)error {
  80. [self cleanup];
  81. if (!error) {
  82. error = [NSError errorWithDomain:@"com.firebase.durabledeeplink" code:-1 userInfo:nil];
  83. }
  84. [_delegate javaScriptExecutor:self failedWithError:error];
  85. }
  86. - (void)cleanup {
  87. _wkWebView.navigationDelegate = nil;
  88. _wkWebView = nil;
  89. }
  90. #pragma mark - WKNavigationDelegate
  91. - (void)webView:(WKWebView *)webView
  92. didFinishNavigation:(null_unspecified WKNavigation *)navigation {
  93. __weak __typeof__(self) weakSelf = self;
  94. // Make sure that the javascript was loaded successfully before calling the method.
  95. [webView evaluateJavaScript:FIRDLTypeofFingerprintJSMethodNameString()
  96. completionHandler:^(id _Nullable typeofResult, NSError *_Nullable typeError) {
  97. if (typeError) {
  98. [weakSelf handleExecutionError:typeError];
  99. return;
  100. }
  101. if ([typeofResult isEqual:@"function"]) {
  102. [webView
  103. evaluateJavaScript:GINFingerprintJSMethodString()
  104. completionHandler:^(id _Nullable result, NSError *_Nullable functionError) {
  105. if ([result isKindOfClass:[NSString class]]) {
  106. [weakSelf handleExecutionResult:result];
  107. } else {
  108. [weakSelf handleExecutionError:nil];
  109. }
  110. }];
  111. } else {
  112. [weakSelf handleExecutionError:nil];
  113. }
  114. }];
  115. }
  116. - (void)webView:(WKWebView *)webView
  117. didFailNavigation:(null_unspecified WKNavigation *)navigation
  118. withError:(NSError *)error {
  119. [self handleExecutionError:error];
  120. }
  121. @end
  122. NS_ASSUME_NONNULL_END