No Description

RCTWebView.m 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // /**
  2. // * Copyright (c) 2015-present, Facebook, Inc.
  3. // *
  4. // * This source code is licensed under the MIT license found in the
  5. // * LICENSE file in the root directory of this source tree.
  6. // */
  7. // #import "IRWebView.h"
  8. // #import <UIKit/UIKit.h>
  9. // #import "RCTAutoInsetsProtocol.h"
  10. // #import "RCTConvert.h"
  11. // #import "RCTEventDispatcher.h"
  12. // #import "RCTLog.h"
  13. // #import "RCTUtils.h"
  14. // #import "RCTView.h"
  15. // #import "UIView+React.h"
  16. // NSString *const RCTJSNavigationScheme = @"react-js-navigation";
  17. // static NSString *const kPostMessageHost = @"postMessage";
  18. // @interface IRWebView () <UIWebViewDelegate, RCTAutoInsetsProtocol>
  19. // @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
  20. // @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
  21. // @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
  22. // @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
  23. // @property (nonatomic, copy) RCTDirectEventBlock onMessage;
  24. // @end
  25. // @implementation IRWebView
  26. // {
  27. // UIWebView *_webView;
  28. // NSString *_injectedJavaScript;
  29. // }
  30. // - (void)dealloc
  31. // {
  32. // _webView.delegate = nil;
  33. // }
  34. // - (instancetype)initWithFrame:(CGRect)frame
  35. // {
  36. // if ((self = [super initWithFrame:frame])) {
  37. // super.backgroundColor = [UIColor clearColor];
  38. // _automaticallyAdjustContentInsets = YES;
  39. // _contentInset = UIEdgeInsetsZero;
  40. // _webView = [[UIWebView alloc] initWithFrame:self.bounds];
  41. // _webView.delegate = self;
  42. // #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
  43. // if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
  44. // _webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  45. // }
  46. // #endif
  47. // [self addSubview:_webView];
  48. // }
  49. // return self;
  50. // }
  51. // RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
  52. // - (void)goForward
  53. // {
  54. // [_webView goForward];
  55. // }
  56. // - (void)goBack
  57. // {
  58. // [_webView goBack];
  59. // }
  60. // - (void)reload
  61. // {
  62. // NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
  63. // if (request.URL && !_webView.request.URL.absoluteString.length) {
  64. // [_webView loadRequest:request];
  65. // }
  66. // else {
  67. // [_webView reload];
  68. // }
  69. // }
  70. // - (void)stopLoading
  71. // {
  72. // [_webView stopLoading];
  73. // }
  74. // - (void)postMessage:(NSString *)message
  75. // {
  76. // NSDictionary *eventInitDict = @{
  77. // @"data": message,
  78. // };
  79. // NSString *source = [NSString
  80. // stringWithFormat:@"document.dispatchEvent(new MessageEvent('message', %@));",
  81. // RCTJSONStringify(eventInitDict, NULL)
  82. // ];
  83. // [_webView stringByEvaluatingJavaScriptFromString:source];
  84. // }
  85. // - (void)injectJavaScript:(NSString *)script
  86. // {
  87. // [_webView stringByEvaluatingJavaScriptFromString:script];
  88. // }
  89. // - (void)setSource:(NSDictionary *)source
  90. // {
  91. // if (![_source isEqualToDictionary:source]) {
  92. // _source = [source copy];
  93. // // Check for a static html source first
  94. // NSString *html = [RCTConvert NSString:source[@"html"]];
  95. // if (html) {
  96. // NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]];
  97. // if (!baseURL) {
  98. // baseURL = [NSURL URLWithString:@"about:blank"];
  99. // }
  100. // [_webView loadHTMLString:html baseURL:baseURL];
  101. // return;
  102. // }
  103. // NSURLRequest *request = [RCTConvert NSURLRequest:source];
  104. // // Because of the way React works, as pages redirect, we actually end up
  105. // // passing the redirect urls back here, so we ignore them if trying to load
  106. // // the same url. We'll expose a call to 'reload' to allow a user to load
  107. // // the existing page.
  108. // if ([request.URL isEqual:_webView.request.URL]) {
  109. // return;
  110. // }
  111. // if (!request.URL) {
  112. // // Clear the webview
  113. // [_webView loadHTMLString:@"" baseURL:nil];
  114. // return;
  115. // }
  116. // [_webView loadRequest:request];
  117. // }
  118. // }
  119. // - (void)layoutSubviews
  120. // {
  121. // [super layoutSubviews];
  122. // _webView.frame = self.bounds;
  123. // }
  124. // - (void)setContentInset:(UIEdgeInsets)contentInset
  125. // {
  126. // _contentInset = contentInset;
  127. // [RCTView autoAdjustInsetsForView:self
  128. // withScrollView:_webView.scrollView
  129. // updateOffset:NO];
  130. // }
  131. // - (void)setScalesPageToFit:(BOOL)scalesPageToFit
  132. // {
  133. // if (_webView.scalesPageToFit != scalesPageToFit) {
  134. // _webView.scalesPageToFit = scalesPageToFit;
  135. // [_webView reload];
  136. // }
  137. // }
  138. // - (BOOL)scalesPageToFit
  139. // {
  140. // return _webView.scalesPageToFit;
  141. // }
  142. // - (void)setBackgroundColor:(UIColor *)backgroundColor
  143. // {
  144. // CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
  145. // self.opaque = _webView.opaque = (alpha == 1.0);
  146. // _webView.backgroundColor = backgroundColor;
  147. // }
  148. // - (UIColor *)backgroundColor
  149. // {
  150. // return _webView.backgroundColor;
  151. // }
  152. // - (NSMutableDictionary<NSString *, id> *)baseEvent
  153. // {
  154. // NSMutableDictionary<NSString *, id> *event = [[NSMutableDictionary alloc] initWithDictionary:@{
  155. // @"url": _webView.request.URL.absoluteString ?: @"",
  156. // @"loading" : @(_webView.loading),
  157. // @"title": [_webView stringByEvaluatingJavaScriptFromString:@"document.title"],
  158. // @"canGoBack": @(_webView.canGoBack),
  159. // @"canGoForward" : @(_webView.canGoForward),
  160. // }];
  161. // return event;
  162. // }
  163. // - (void)refreshContentInset
  164. // {
  165. // [RCTView autoAdjustInsetsForView:self
  166. // withScrollView:_webView.scrollView
  167. // updateOffset:YES];
  168. // }
  169. // #pragma mark - UIWebViewDelegate methods
  170. // - (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
  171. // navigationType:(UIWebViewNavigationType)navigationType
  172. // {
  173. // BOOL isJSNavigation = [request.URL.scheme isEqualToString:RCTJSNavigationScheme];
  174. // static NSDictionary<NSNumber *, NSString *> *navigationTypes;
  175. // static dispatch_once_t onceToken;
  176. // dispatch_once(&onceToken, ^{
  177. // navigationTypes = @{
  178. // @(UIWebViewNavigationTypeLinkClicked): @"click",
  179. // @(UIWebViewNavigationTypeFormSubmitted): @"formsubmit",
  180. // @(UIWebViewNavigationTypeBackForward): @"backforward",
  181. // @(UIWebViewNavigationTypeReload): @"reload",
  182. // @(UIWebViewNavigationTypeFormResubmitted): @"formresubmit",
  183. // @(UIWebViewNavigationTypeOther): @"other",
  184. // };
  185. // });
  186. // // skip this for the JS Navigation handler
  187. // if (!isJSNavigation && _onShouldStartLoadWithRequest) {
  188. // NSMutableDictionary<NSString *, id> *event = [self baseEvent];
  189. // [event addEntriesFromDictionary: @{
  190. // @"url": (request.URL).absoluteString,
  191. // @"navigationType": navigationTypes[@(navigationType)]
  192. // }];
  193. // if (![self.delegate webView:self
  194. // shouldStartLoadForRequest:event
  195. // withCallback:_onShouldStartLoadWithRequest]) {
  196. // return NO;
  197. // }
  198. // }
  199. // if (_onLoadingStart) {
  200. // // We have this check to filter out iframe requests and whatnot
  201. // BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
  202. // if (isTopFrame) {
  203. // NSMutableDictionary<NSString *, id> *event = [self baseEvent];
  204. // [event addEntriesFromDictionary: @{
  205. // @"url": (request.URL).absoluteString,
  206. // @"navigationType": navigationTypes[@(navigationType)]
  207. // }];
  208. // _onLoadingStart(event);
  209. // }
  210. // }
  211. // if (isJSNavigation && [request.URL.host isEqualToString:kPostMessageHost]) {
  212. // NSString *data = request.URL.query;
  213. // data = [data stringByReplacingOccurrencesOfString:@"+" withString:@" "];
  214. // data = [data stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  215. // NSMutableDictionary<NSString *, id> *event = [self baseEvent];
  216. // [event addEntriesFromDictionary: @{
  217. // @"data": data,
  218. // }];
  219. // NSString *source = @"document.dispatchEvent(new MessageEvent('message:received'));";
  220. // [_webView stringByEvaluatingJavaScriptFromString:source];
  221. // _onMessage(event);
  222. // }
  223. // // JS Navigation handler
  224. // return !isJSNavigation;
  225. // }
  226. // - (void)webView:(__unused UIWebView *)webView didFailLoadWithError:(NSError *)error
  227. // {
  228. // if (_onLoadingError) {
  229. // if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
  230. // // NSURLErrorCancelled is reported when a page has a redirect OR if you load
  231. // // a new URL in the WebView before the previous one came back. We can just
  232. // // ignore these since they aren't real errors.
  233. // // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
  234. // return;
  235. // }
  236. // if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102) {
  237. // // Error code 102 "Frame load interrupted" is raised by the UIWebView if
  238. // // its delegate returns FALSE from webView:shouldStartLoadWithRequest:navigationType
  239. // // when the URL is from an http redirect. This is a common pattern when
  240. // // implementing OAuth with a WebView.
  241. // return;
  242. // }
  243. // NSMutableDictionary<NSString *, id> *event = [self baseEvent];
  244. // [event addEntriesFromDictionary:@{
  245. // @"domain": error.domain,
  246. // @"code": @(error.code),
  247. // @"description": error.localizedDescription,
  248. // }];
  249. // _onLoadingError(event);
  250. // }
  251. // }
  252. // - (void)webViewDidFinishLoad:(UIWebView *)webView
  253. // {
  254. // if (_messagingEnabled) {
  255. // #if RCT_DEV
  256. // // See isNative in lodash
  257. // NSString *testPostMessageNative = @"String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')";
  258. // BOOL postMessageIsNative = [
  259. // [webView stringByEvaluatingJavaScriptFromString:testPostMessageNative]
  260. // isEqualToString:@"true"
  261. // ];
  262. // if (!postMessageIsNative) {
  263. // RCTLogError(@"Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined");
  264. // }
  265. // #endif
  266. // NSString *source = [NSString stringWithFormat:
  267. // @"(function() {"
  268. // "window.originalPostMessage = window.postMessage;"
  269. // "var messageQueue = [];"
  270. // "var messagePending = false;"
  271. // "function processQueue() {"
  272. // "if (!messageQueue.length || messagePending) return;"
  273. // "messagePending = true;"
  274. // "window.location = '%@://%@?' + encodeURIComponent(messageQueue.shift());"
  275. // "}"
  276. // "window.postMessage = function(data) {"
  277. // "messageQueue.push(String(data));"
  278. // "processQueue();"
  279. // "};"
  280. // "document.addEventListener('message:received', function(e) {"
  281. // "messagePending = false;"
  282. // "processQueue();"
  283. // "});"
  284. // "})();", RCTJSNavigationScheme, kPostMessageHost
  285. // ];
  286. // [webView stringByEvaluatingJavaScriptFromString:source];
  287. // }
  288. // if (_injectedJavaScript != nil) {
  289. // NSString *jsEvaluationValue = [webView stringByEvaluatingJavaScriptFromString:_injectedJavaScript];
  290. // NSMutableDictionary<NSString *, id> *event = [self baseEvent];
  291. // event[@"jsEvaluationValue"] = jsEvaluationValue;
  292. // _onLoadingFinish(event);
  293. // }
  294. // // we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
  295. // else if (_onLoadingFinish && !webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
  296. // _onLoadingFinish([self baseEvent]);
  297. // }
  298. // }
  299. // @end