├── .vscode └── settings.json ├── example ├── .watchmanconfig ├── .gitattributes ├── .babelrc ├── .buckconfig ├── ios │ ├── example │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ └── LaunchScreen.xib │ └── example.xcodeproj │ │ ├── xcshareddata │ │ └── xcschemes │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ │ └── project.pbxproj ├── package.json ├── .gitignore ├── index.ios.js └── .flowconfig ├── .npmignore ├── WKWebView.windows.js ├── index.js ├── WKWebView.android.js ├── .gitignore ├── ios ├── RCTWKWebView │ ├── WKProcessPool+SharedProcessPool.h │ ├── CRAWKWebViewManager.h │ ├── WeakScriptMessageDelegate.h │ ├── WKProcessPool+SharedProcessPool.m │ ├── WeakScriptMessageDelegate.m │ ├── CRAWKWebView.h │ ├── CRAWKWebViewManager.m │ └── CRAWKWebView.m └── RCTWKWebView.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── insraq.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── xcuserdata │ └── insraq.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── RCTWKWebView.xcscheme │ └── project.pbxproj ├── react-native-wkwebview.podspec ├── LICENSE ├── yarn.lock ├── package.json ├── README.md └── WKWebView.ios.js /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | example -------------------------------------------------------------------------------- /WKWebView.windows.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = {}; 4 | -------------------------------------------------------------------------------- /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "module:metro-react-native-babel-preset" 4 | ] 5 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import WKWebView from './WKWebView'; 4 | 5 | export default WKWebView; 6 | -------------------------------------------------------------------------------- /WKWebView.android.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { 4 | WebView, 5 | } from 'react-native'; 6 | 7 | export default WebView; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */.DS_Store 3 | 4 | ios/RCTWKWebView.xcodeproj/xcuserdata/* 5 | ios/RCTWKWebView.xcodeproj/project.xcworkspace/xcuserdata/* 6 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/WKProcessPool+SharedProcessPool.h: -------------------------------------------------------------------------------- 1 | @interface WKProcessPool (SharedProcessPool) 2 | + (WKProcessPool*)sharedProcessPool; 3 | @end 4 | -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/CRAWKWebViewManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface RCTConvert (UIScrollView) 5 | 6 | @end 7 | 8 | @interface CRAWKWebViewManager : RCTViewManager 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /ios/RCTWKWebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/RCTWKWebView.xcodeproj/project.xcworkspace/xcuserdata/insraq.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CRAlpha/react-native-wkwebview/HEAD/ios/RCTWKWebView.xcodeproj/project.xcworkspace/xcuserdata/insraq.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ios/RCTWKWebView/WeakScriptMessageDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | 5 | // Trampoline object to avoid retain cycle with the script message handler 6 | @interface WeakScriptMessageDelegate : NSObject 7 | 8 | @property (nonatomic, weak) id scriptDelegate; 9 | 10 | - (instancetype)initWithDelegate:(id)scriptDelegate; 11 | 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/WKProcessPool+SharedProcessPool.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "WKProcessPool+SharedProcessPool.h" 4 | 5 | @implementation WKProcessPool (SharedProcessPool) 6 | 7 | + (WKProcessPool*)sharedProcessPool { 8 | static WKProcessPool* _sharedProcessPool; 9 | static dispatch_once_t onceToken; 10 | dispatch_once(&onceToken, ^{ 11 | _sharedProcessPool = [[WKProcessPool alloc] init]; 12 | }); 13 | return _sharedProcessPool; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example/ios/example/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest" 8 | }, 9 | "dependencies": { 10 | "metro-react-native-babel-preset": "^0.48.0", 11 | "prop-types": "15.6.0", 12 | "react": "16.5.0", 13 | "react-native": "0.57", 14 | "react-native-wkwebview-reborn": "file:../" 15 | }, 16 | "devDependencies": { 17 | "babel-jest": "19.0.0", 18 | "babel-preset-react-native": "1.9.1" 19 | }, 20 | "jest": { 21 | "preset": "react-native" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/WeakScriptMessageDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | #import "WeakScriptMessageDelegate.h" 3 | 4 | @implementation WeakScriptMessageDelegate 5 | 6 | - (instancetype)initWithDelegate:(id)scriptDelegate 7 | { 8 | self = [super init]; 9 | if (self) { 10 | _scriptDelegate = scriptDelegate; 11 | } 12 | return self; 13 | } 14 | 15 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 16 | { 17 | [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ios/RCTWKWebView.xcodeproj/xcuserdata/insraq.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RCTWKWebView.xcscheme 8 | 9 | orderHint 10 | 25 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 097457991D2A440A000D9368 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /react-native-wkwebview.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "react-native-wkwebview" 7 | s.version = package["version"] 8 | s.summary = "React Native WKWebView for iOS" 9 | s.author = "Ruoyu Sun (https://github.com/insraq)" 10 | 11 | s.homepage = "https://github.com/CRAlpha/react-native-wkwebview" 12 | 13 | s.license = "MIT" 14 | s.platform = :ios, "8.0" 15 | 16 | s.source = { :git => "https://github.com/CRAlpha/react-native-wkwebview.git", :tag => "v#{s.version}" } 17 | 18 | s.source_files = "ios/RCTWKWebView/*.{h,m}" 19 | 20 | s.dependency "React" 21 | end 22 | -------------------------------------------------------------------------------- /example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jordan Sexton 4 | Copyright (c) 2016-2018 Ruoyu Sun 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /example/index.ios.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | AppRegistry, 4 | StyleSheet, 5 | Text, 6 | View 7 | } from 'react-native'; 8 | import WkWebView from 'react-native-wkwebview-reborn'; 9 | 10 | export default class example extends Component { 11 | render() { 12 | return ( 13 | 14 | this.webview = c} 19 | sendCookies={true} 20 | source={{ uri: 'https://example.org/' }} 21 | onMessage={(e) => console.log(e.nativeEvent)} 22 | onNavigationResponse={(e) => console.log(e.nativeEvent)} 23 | injectedJavaScript="window.postMessage('Hello from WkWebView'); document.addEventListener('message', function(e) { alert(e.data); });" 24 | /> 25 | this.webview.reload()}>Reload 26 | this.webview.postMessage("Hello from React Native")}>Post Message 27 | 28 | ); 29 | } 30 | } 31 | 32 | AppRegistry.registerComponent('example', () => example); 33 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"example" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | experimental.strict_type_args=true 30 | 31 | munge_underscores=true 32 | 33 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 34 | 35 | suppress_type=$FlowIssue 36 | suppress_type=$FlowFixMe 37 | suppress_type=$FixMe 38 | 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 42 | 43 | unsafe.enable_getters_and_setters=true 44 | 45 | [version] 46 | ^0.38.0 47 | -------------------------------------------------------------------------------- /example/ios/example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/CRAWKWebView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | 5 | @class CRAWKWebView; 6 | 7 | /** 8 | * Special scheme used to pass messages to the injectedJavaScript 9 | * code without triggering a page load. Usage: 10 | * 11 | * window.location.href = RCTJSNavigationScheme + '://hello' 12 | */ 13 | extern NSString *const RCTJSNavigationScheme; 14 | 15 | @protocol CRAWKWebViewDelegate 16 | 17 | - (BOOL)webView:(CRAWKWebView *)webView 18 | shouldStartLoadForRequest:(NSMutableDictionary *)request 19 | withCallback:(RCTDirectEventBlock)callback; 20 | 21 | @end 22 | 23 | @interface CRAWKWebView : RCTView 24 | 25 | - (instancetype)initWithProcessPool:(WKProcessPool *)processPool; 26 | 27 | @property (nonatomic, weak) id delegate; 28 | 29 | @property (nonatomic, copy) NSDictionary *source; 30 | @property (nonatomic, assign) UIEdgeInsets contentInset; 31 | @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets; 32 | @property (nonatomic, assign) BOOL messagingEnabled; 33 | @property (nonatomic, assign) BOOL allowsLinkPreview; 34 | @property (nonatomic, assign) BOOL openNewWindowInWebView; 35 | @property (nonatomic, assign) BOOL injectJavaScriptForMainFrameOnly; 36 | @property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly; 37 | @property (nonatomic, copy) NSString *injectJavaScript; 38 | @property (nonatomic, copy) NSString *injectedJavaScript; 39 | @property (nonatomic, assign) BOOL hideKeyboardAccessoryView; 40 | @property (nonatomic, assign) BOOL keyboardDisplayRequiresUserAction; 41 | 42 | 43 | - (void)goForward; 44 | - (void)goBack; 45 | - (BOOL)canGoBack; 46 | - (BOOL)canGoForward; 47 | - (void)reload; 48 | - (void)stopLoading; 49 | - (void)postMessage:(NSString *)message; 50 | - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *error))completionHandler; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | asap@~2.0.3: 6 | version "2.0.6" 7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" 8 | 9 | core-js@^1.0.0: 10 | version "1.2.7" 11 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" 12 | 13 | encoding@^0.1.11: 14 | version "0.1.12" 15 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 16 | dependencies: 17 | iconv-lite "~0.4.13" 18 | 19 | fbjs@^0.8.3: 20 | version "0.8.16" 21 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" 22 | dependencies: 23 | core-js "^1.0.0" 24 | isomorphic-fetch "^2.1.1" 25 | loose-envify "^1.0.0" 26 | object-assign "^4.1.0" 27 | promise "^7.1.1" 28 | setimmediate "^1.0.5" 29 | ua-parser-js "^0.7.9" 30 | 31 | iconv-lite@~0.4.13: 32 | version "0.4.19" 33 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" 34 | 35 | is-stream@^1.0.1: 36 | version "1.1.0" 37 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 38 | 39 | isomorphic-fetch@^2.1.1: 40 | version "2.2.1" 41 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" 42 | dependencies: 43 | node-fetch "^1.0.1" 44 | whatwg-fetch ">=0.10.0" 45 | 46 | js-tokens@^3.0.0: 47 | version "3.0.2" 48 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 49 | 50 | loose-envify@^1.0.0: 51 | version "1.3.1" 52 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 53 | dependencies: 54 | js-tokens "^3.0.0" 55 | 56 | node-fetch@^1.0.1: 57 | version "1.7.3" 58 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" 59 | dependencies: 60 | encoding "^0.1.11" 61 | is-stream "^1.0.1" 62 | 63 | object-assign@^4.1.0: 64 | version "4.1.1" 65 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 66 | 67 | promise@^7.1.1: 68 | version "7.3.1" 69 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" 70 | dependencies: 71 | asap "~2.0.3" 72 | 73 | setimmediate@^1.0.5: 74 | version "1.0.5" 75 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 76 | 77 | ua-parser-js@^0.7.9: 78 | version "0.7.17" 79 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" 80 | 81 | whatwg-fetch@>=0.10.0: 82 | version "2.0.3" 83 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" 84 | -------------------------------------------------------------------------------- /ios/RCTWKWebView.xcodeproj/xcuserdata/insraq.xcuserdatad/xcschemes/RCTWKWebView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /example/ios/example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 62 | 68 | 69 | 70 | 71 | 72 | 78 | 79 | 80 | 81 | 82 | 83 | 94 | 96 | 102 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 118 | 120 | 126 | 127 | 128 | 129 | 131 | 132 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_args": [ 3 | [ 4 | { 5 | "raw": "react-native-wkwebview-reborn@file:../", 6 | "scope": null, 7 | "escapedName": "react-native-wkwebview-reborn", 8 | "name": "react-native-wkwebview-reborn", 9 | "rawSpec": "file:../", 10 | "spec": "/Users/insraq/Projects/react-native-wkwebview", 11 | "type": "directory" 12 | }, 13 | "/Users/insraq/Projects/react-native-wkwebview/example" 14 | ] 15 | ], 16 | "_from": "..", 17 | "_id": "react-native-wkwebview-reborn@1.2.0", 18 | "_inCache": true, 19 | "_location": "/react-native-wkwebview-reborn", 20 | "_phantomChildren": {}, 21 | "_requested": { 22 | "raw": "react-native-wkwebview-reborn@file:../", 23 | "scope": null, 24 | "escapedName": "react-native-wkwebview-reborn", 25 | "name": "react-native-wkwebview-reborn", 26 | "rawSpec": "file:../", 27 | "spec": "/Users/insraq/Projects/react-native-wkwebview", 28 | "type": "directory" 29 | }, 30 | "_requiredBy": [ 31 | "/" 32 | ], 33 | "_resolved": "file:..", 34 | "_shasum": "810755db27687d6f5178c2ed44e700e96a558f26", 35 | "_shrinkwrap": null, 36 | "_spec": "react-native-wkwebview-reborn@file:../", 37 | "_where": "/Users/insraq/Projects/react-native-wkwebview/example", 38 | "author": { 39 | "name": "Ruoyu Sun", 40 | "email": "ruoysun@gmail.com" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/CRAlpha/react-native-wkwebview/issues" 44 | }, 45 | "dependencies": { 46 | "fbjs": "^0.8.3" 47 | }, 48 | "description": "React Native WKWebView for iOS", 49 | "devDependencies": {}, 50 | "gitHead": "5c1809c67ca87e531727b51f751db0e71dfebf9b", 51 | "homepage": "https://github.com/CRAlpha/react-native-wkwebview", 52 | "keywords": [ 53 | "react", 54 | "native", 55 | "wkwebview", 56 | "webview", 57 | "ios" 58 | ], 59 | "license": "MIT", 60 | "main": "index.js", 61 | "name": "react-native-wkwebview-reborn", 62 | "optionalDependencies": {}, 63 | "peerDependencies": { 64 | "prop-types": "^15.6.0" 65 | }, 66 | "pre-push#master": [ 67 | "lint" 68 | ], 69 | "readme": "## WKWebView Component for React Native\n\n[![npm version](https://badge.fury.io/js/react-native-wkwebview-reborn.svg)](https://badge.fury.io/js/react-native-wkwebview-reborn)\n\nReact Native comes with [WebView](http://facebook.github.io/react-native/docs/webview.html) component, which uses UIWebView on iOS. This component uses [WKWebView](http://nshipster.com/wkwebkit/) introduced in iOS 8 with all the performance boost. **Deployment Target >= iOS 8.0 is required**\n\n### Install\n\n**Alternative #1**\n\n1. Install from npm (note the postfix in the package name): `npm install react-native-wkwebview-reborn`\n2. In the XCode's \"Project navigator\", right click on your project's Libraries folder ➜ Add Files to <...>\n3. Go to node_modules ➜ react-native-wkwebview ➜ ios ➜ select RCTWKWebView folder and create a group\n4. Compile and profit (Remember to set Minimum Deployment Target = 8.0)\n\n**Alternative #2**\n\n1. Install from npm (note the postfix in the package name): `npm install react-native-wkwebview-reborn`\n2. run `rnpm link`\n\n**Notes to iOS 8:**\n\nIf you install from using Alterntive #2, you might encounter bugs in iOS 8.2 (We've only tested this version) where the app crashes with `dyld_fatal_error`.\nThis can be solved using Alternative #1. We were still unable to find the cause of the first bug so I recommend that you link the library using Alternative #1.\n\n\n### Usage\n\n```\nimport WKWebView from 'react-native-wkwebview-reborn';\n```\n\nTry replacing your existing `WebView` with `WKWebView` and it should work in most cases.\n\n**Note on version**\n\nReact Native 0.40 breaks library compatibility, so we currently have two branches:\n\n- 0.X.X: for RN < 0.40\n- 1.X.X: for RN >= 0.40\n\nPlease choose accordingly. We will try to make sure both branches have the same set of features until most people have upraded to 0.40\n\n### Compatibility with UIWebView\n\nWKWebView aims to be a drop-in replacement for UIWebView. However, some legacy UIWebView properties are not supported.\n\n**Additional props:**\n\n- onProgress\n\nA callback to get the loading progress of WKWebView. Derived from [`estimatedProgress`](https://developer.apple.com/library/ios/documentation/WebKit/Reference/WKWebView_Ref/#//apple_ref/occ/instp/WKWebView/estimatedProgress) property.\n\n```\n console.log(progress)} />\n```\n\n`progress` is a double between 0 and 1.\n\n- openNewWindowInWebView (New in 0.4.0)\n\nIf set to true, links with `target=\"_blank\"` or `window.open` will be opened in the current webview, not in Safari.\nDefault is false.\n\n- sendCookies\n\nSet `sendCookies` to true to copy cookies from `sharedHTTPCookieStorage` when calling loadRequest. This emulates the behavior of react-native's `WebView` component.\n\n- source={{file: '', allowingReadAccessToURL: '' }}\n\nThis allows WKWebView loads a local HTML file. Please note the underlying API is only introduced in iOS 9+. So in iOS 8, it will simple ignores these two properties.\nIt allows you to provide a fallback URL for iOS 8 users.\n\n```\n\n```\n\n**From WKWebview -> React Native (New in 0.3.0)**\n\n- onMessage\n\nThis utilizes the message handlers in WKWebView and allows you to post message from webview to React Native. For example:\n\n```\n console.log(e)} />\n```\n\nThen in your webview, you can post message to React Native using\n\n```\nwindow.webkit.messageHandlers.reactNative.postMessage({data: 'hello!'});\n```\n\nThen your React Native should have\n\n```\n{name: 'reactNative', body: {data: 'hello!'}}\n```\n\nThe data serialization flow is as follows:\n\nJS --- (via WKWebView) --> ObjC --- (via React Native Bridge) ---> JS\n\nSo I recommend to keep your data simple and JSON-friendly.\n\n**From React Native -> WkWebView (New in 0.3.0)**\n\nThere is a `evaluateJavaScript` method on WKWebView, which does exactly what its name suggests. To send message from React Native to WebView,\nyou can define a callback method on your WebView:\n\n```\nwindow.receivedMessageFromReactNative = function(data) {\n // Code here\n console.log(data);\n}\n```\n\nThen you can send message from React Native with this method call:\n\n```\n// \nthis.refs.webview.evaluateJavaScript('receivedMessageFromReactNative(\"Hello from the other side.\")');\n```\n\n**Currently supported props are:**\n\n- automaticallyAdjustContentInsets\n- contentInset\n- html (deprecated)\n- injectedJavaScript\n- onError\n- onLoad\n- onLoadEnd\n- onLoadStart\n- onNavigationStateChange\n- renderError\n- renderLoading\n- source\n- startInLoadingState\n- style\n- url (deprecated)\n- bounces\n- onShouldStartLoadWithRequest\n- pagingEnabled\n- scrollEnabled\n\n**Unsupported props are:**\n\n- mediaPlaybackRequiresUserAction\n- scalesPageToFit\n- domStorageEnabled\n- javaScriptEnabled\n- allowsInlineMediaPlayback\n- decelerationRate\n\nIf you look at the source, the JavaScript side is mostly derived from React Native's WebView. The Objective C side mostly deals with the API difference between UIWebView and WKWebView.\n\n### Contribute\n\nWe battle test this component against our app. However, we haven't use all the props so if something does not work as expected, please open an issue or PR.\n", 70 | "readmeFilename": "README.md", 71 | "repository": { 72 | "type": "git", 73 | "url": "git+https://github.com/CRAlpha/react-native-wkwebview.git" 74 | }, 75 | "scripts": { 76 | "lint": "eslint --ext .js --ext .jsx .", 77 | "sync-from-example": "cp ./example/node_modules/react-native-wkwebview-reborn/*.js ./;cp -r ./example/node_modules/react-native-wkwebview-reborn/ios ./", 78 | "sync-to-example": "cp ./*.js ./example/node_modules/react-native-wkwebview-reborn/;cp -r ./ios ./example/node_modules/react-native-wkwebview-reborn/" 79 | }, 80 | "version": "2.0.0" 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Inactive Repository Notice! 2 | 3 | This package is no longer maintained, you should probably consider using [react-native-webview](https://github.com/react-native-webview/react-native-webview) if you start a new project. 4 | 5 | ## WKWebView Component for React Native 6 | 7 | [![npm version](https://badge.fury.io/js/react-native-wkwebview-reborn.svg)](https://badge.fury.io/js/react-native-wkwebview-reborn) 8 | 9 | React Native comes with [WebView](http://facebook.github.io/react-native/docs/webview.html) component, which uses UIWebView on iOS. This component uses [WKWebView](http://nshipster.com/wkwebkit/) introduced in iOS 8 with all the performance boost. 10 | 11 | **Deployment Target >= iOS 8.0 is required** *(which is React Native's current minimum deployment target anyway).* 12 | 13 | ### Install 14 | 15 | 1. Install from npm (note the postfix in the package name): `npm install react-native-wkwebview-reborn` 16 | 2. run `react-native link react-native-wkwebview-reborn` 17 | 18 | **Manual alternative** 19 | 20 | 1. Install from npm (note the postfix in the package name): `npm install react-native-wkwebview-reborn` 21 | 2. In the XCode's "Project navigator", right click on your project's Libraries folder ➜ Add Files to <...> 22 | 3. Go to node_modules ➜ react-native-wkwebview-reborn ➜ ios ➜ select `RCTWKWebView.xcodeproj` 23 | 4. Go your build target ➜ Build Phases ➜ Link Binary With Libraries, click "+" and select `libRCTWkWebView.a` (see the following screenshot for reference) 24 | ![Linking](https://user-images.githubusercontent.com/608221/28060167-0650e3f4-6659-11e7-8085-7a8c2615f90f.png) 25 | 5. Compile and profit (Remember to set Minimum Deployment Target = 8.0) 26 | 27 | 28 | ### Usage 29 | 30 | ```js 31 | import WKWebView from 'react-native-wkwebview-reborn'; 32 | ``` 33 | 34 | Try replacing your existing `WebView` with `WKWebView` and it should work in most cases. 35 | 36 | For React Native >= 0.57, use version 2.x; for React Native < 0.40, use version 0.x. 37 | 38 | ### Compatibility with UIWebView 39 | 40 | WKWebView aims to be a drop-in replacement for UIWebView. However, some legacy UIWebView properties are not supported. 41 | 42 | **Since 1.14.0, WkWebView supports `onMessage` and `postMessage` as in the default WebView. You can refer to the React Native documentation or the `example` project. For advanced or customized usage, please refer to [Advanced Communication between React Native and WkWebView](#advanced-communication-between-react-native-and-wkwebview).** 43 | 44 | #### Additional props: 45 | 46 | - **onProgress** 47 | 48 | A callback to get the loading progress of WKWebView. Derived from [`estimatedProgress`](https://developer.apple.com/library/ios/documentation/WebKit/Reference/WKWebView_Ref/#//apple_ref/occ/instp/WKWebView/estimatedProgress) property. 49 | 50 | ```js 51 | console.log(progress)} /> 52 | ``` 53 | 54 | `progress` is a double between 0 and 1. 55 | 56 | - **onNavigationResponse** 57 | 58 | A callback to get response headers, http status code and http localized status code. 59 | 60 | - **openNewWindowInWebView** 61 | 62 | If set to true, links with `target="_blank"` or `window.open` will be opened in the current webview, not in Safari. Default is false. 63 | 64 | - **sendCookies** 65 | 66 | Set `sendCookies` to true to copy cookies from `sharedHTTPCookieStorage` when calling loadRequest. This emulates the behavior of react-native's `WebView` component. You can set cookies using `react-native-cookies` Default is false. 67 | 68 | - **source={{file: '', allowingReadAccessToURL: '' }}** 69 | 70 | This allows WKWebView loads a local HTML file. Please note the underlying API is only introduced in iOS 9+. So in iOS 8, it will simple ignores these two properties. 71 | It allows you to provide a fallback URL for iOS 8 users. 72 | 73 | ```js 74 | 75 | ``` 76 | 77 | You can also use the `require` syntax (sendCookies and userAgent will be ignored) 78 | 79 | ```js 80 | 81 | ``` 82 | 83 | - **userAgent="MyUserAgent" (or customUserAgent="...")** 84 | 85 | Set a custom user agent for WKWebView. Note this only works on iOS 9+. Previous version will simply ignore this props. 86 | 87 | - **hideKeyboardAccessoryView** 88 | 89 | This will hide the keyboard accessory view (`<` `>` and `Done`). Default is false. 90 | 91 | - **allowsLinkPreview** 92 | 93 | A Boolean value that determines whether pressing on a link displays a preview of the destination for the link. This props is available on devices that support 3D Touch. In iOS 10 and later, the default value is true; before that, the default value is false. 94 | 95 | - **contentInsetAdjustmentBehavior** 96 | 97 | This property specifies how the safe area insets are used to modify the content area of the scroll view. The default value of this property is "never". Available on iOS 11 and later. Possible values are "automatic", "scrollableAxes", "never", "always". **New in 1.16.0** 98 | 99 | - **keyboardDisplayRequiresUserAction** 100 | 101 | Enables focusing an input inside a webview and showing the keyboard *programatically*. **New in 1.20.0** 102 | 103 | - **keyboardDismissMode** 104 | 105 | Sets the manner in which the keyboard is dismissed when a drag begins in the scroll view. Possible values are "none", "on-drag" and "interactive". Default to "none". 106 | 107 | - **injectJavaScript, injectJavaScriptForMainFrameOnly** 108 | 109 | Add JavaScript at document start, see [WKUserScriptInjectionTimeAtDocumentStart](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentstart?language=objc). **New in 1.20.0** 110 | 111 | - **injectedJavaScript, injectedJavaScriptForMainFrameOnly** 112 | 113 | Add JavaScript at document end. Since 1.20.0, the implementation has been changed to use WKUserScript. 114 | 115 | - **allowsBackForwardNavigationGestures** 116 | 117 | Enable horizontal swipe gestures will trigger back-forward navigations. Derived from [`allowsBackForwardNavigationGestures`](https://developer.apple.com/documentation/webkit/wkwebview/1414995-allowsbackforwardnavigationgestu) property. 118 | 119 | #### Currently supported props are: 120 | 121 | - automaticallyAdjustContentInsets 122 | - contentInset 123 | - html (deprecated) 124 | - injectJavaScript 125 | - injectedJavaScript 126 | - onError 127 | - onLoad 128 | - onLoadEnd 129 | - onLoadStart 130 | - onNavigationStateChange 131 | - renderError 132 | - renderLoading 133 | - source 134 | - startInLoadingState 135 | - style 136 | - url (deprecated) 137 | - bounces 138 | - onShouldStartLoadWithRequest 139 | - pagingEnabled 140 | - scrollEnabled 141 | - directionalLockEnabled 142 | 143 | #### Unsupported props are: 144 | 145 | - mediaPlaybackRequiresUserAction 146 | - scalesPageToFit 147 | - domStorageEnabled 148 | - javaScriptEnabled 149 | - allowsInlineMediaPlayback 150 | - decelerationRate 151 | 152 | ### Advanced Communication between React Native and WkWebView 153 | 154 | 155 | #### Communication from WKWebview to React Native 156 | 157 | - **onMessage** 158 | 159 | This utilizes the message handlers in WKWebView and allows you to post message from webview to React Native. For example: 160 | 161 | ```js 162 | console.log(e)} /> 163 | ``` 164 | 165 | Then in your webview, you can post message to React Native using 166 | 167 | ```js 168 | window.webkit.messageHandlers.reactNative.postMessage({message: 'hello!'}); 169 | ``` 170 | 171 | or (since 1.14.0) 172 | 173 | ```js 174 | window.postMessage({message: 'hello!'}); 175 | ``` 176 | 177 | Then you can access the nativeEvent in React Native using the event object returned 178 | 179 | ```js 180 | e.nativeEvent => { 181 | name: 'reactNative', 182 | data: { 183 | message: 'hello!' 184 | } 185 | } 186 | ``` 187 | 188 | The data serialization flow is as follows: 189 | 190 | ``` 191 | JS — (via WKWebView) --> ObjC --- (via React Native Bridge) ---> JS 192 | ``` 193 | 194 | So I recommend to keep your data simple and JSON-friendly. 195 | 196 | #### Communication from React Native to WkWebView 197 | 198 | There is a `evaluateJavaScript` method on WKWebView, which does exactly what its name suggests. To send message from React Native to WebView, 199 | you can define a callback method on your WebView: 200 | 201 | ```js 202 | window.receivedMessageFromReactNative = function(data) { 203 | // Code here 204 | console.log(data); 205 | } 206 | ``` 207 | 208 | Then you can send message from React Native with this method call: 209 | 210 | ```js 211 | // { this.webview = ref; }} /> 212 | this.webview.evaluateJavaScript('receivedMessageFromReactNative("Hello from the other side.")'); 213 | ``` 214 | 215 | If you look at the source, the JavaScript side is mostly derived from React Native's WebView. The Objective C side mostly deals with the API difference between UIWebView and WKWebView. 216 | 217 | ### Contribute 218 | 219 | We battle test this component against our app. However, we haven't use all the props so if something does not work as expected, please open an issue or PR. 220 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/CRAWKWebViewManager.m: -------------------------------------------------------------------------------- 1 | #import "CRAWKWebViewManager.h" 2 | 3 | #import "CRAWKWebView.h" 4 | #import "WKProcessPool+SharedProcessPool.h" 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | 11 | #import 12 | 13 | @implementation RCTConvert (UIScrollView) 14 | 15 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ 16 | RCT_ENUM_CONVERTER(UIScrollViewContentInsetAdjustmentBehavior, (@{ 17 | @"automatic": @(UIScrollViewContentInsetAdjustmentAutomatic), 18 | @"scrollableAxes": @(UIScrollViewContentInsetAdjustmentScrollableAxes), 19 | @"never": @(UIScrollViewContentInsetAdjustmentNever), 20 | @"always": @(UIScrollViewContentInsetAdjustmentAlways), 21 | }), UIScrollViewContentInsetAdjustmentNever, integerValue) 22 | #endif 23 | 24 | RCT_ENUM_CONVERTER(UIScrollViewKeyboardDismissMode, (@{ 25 | @"none": @(UIScrollViewKeyboardDismissModeNone), 26 | @"on-drag": @(UIScrollViewKeyboardDismissModeOnDrag), 27 | @"interactive": @(UIScrollViewKeyboardDismissModeInteractive), 28 | }), UIScrollViewKeyboardDismissModeNone, integerValue) 29 | 30 | @end 31 | 32 | @interface CRAWKWebViewManager () 33 | 34 | @end 35 | 36 | @implementation CRAWKWebViewManager 37 | { 38 | NSConditionLock *_shouldStartLoadLock; 39 | BOOL _shouldStartLoad; 40 | } 41 | 42 | RCT_EXPORT_MODULE() 43 | 44 | - (UIView *)view 45 | { 46 | CRAWKWebView *webView = [[CRAWKWebView alloc] initWithProcessPool:[WKProcessPool sharedProcessPool]]; 47 | webView.delegate = self; 48 | return webView; 49 | } 50 | 51 | RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary) 52 | RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL) 53 | RCT_REMAP_VIEW_PROPERTY(pagingEnabled, _webView.scrollView.pagingEnabled, BOOL) 54 | RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL) 55 | RCT_REMAP_VIEW_PROPERTY(keyboardDismissMode, _webView.scrollView.keyboardDismissMode, UIScrollViewKeyboardDismissMode) 56 | RCT_REMAP_VIEW_PROPERTY(directionalLockEnabled, _webView.scrollView.directionalLockEnabled, BOOL) 57 | RCT_REMAP_VIEW_PROPERTY(allowsBackForwardNavigationGestures, _webView.allowsBackForwardNavigationGestures, BOOL) 58 | RCT_EXPORT_VIEW_PROPERTY(injectJavaScriptForMainFrameOnly, BOOL) 59 | RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptForMainFrameOnly, BOOL) 60 | RCT_EXPORT_VIEW_PROPERTY(injectJavaScript, NSString) 61 | RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString) 62 | RCT_EXPORT_VIEW_PROPERTY(openNewWindowInWebView, BOOL) 63 | RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets) 64 | RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL) 65 | RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock) 66 | RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock) 67 | RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock) 68 | RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock) 69 | RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock) 70 | RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock) 71 | RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) 72 | RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL) 73 | RCT_EXPORT_VIEW_PROPERTY(keyboardDisplayRequiresUserAction, BOOL) 74 | RCT_EXPORT_VIEW_PROPERTY(messagingEnabled, BOOL) 75 | RCT_EXPORT_VIEW_PROPERTY(allowsLinkPreview, BOOL) 76 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ 77 | RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior) 78 | #endif 79 | RCT_EXPORT_VIEW_PROPERTY(onNavigationResponse, RCTDirectEventBlock) 80 | 81 | RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag) 82 | { 83 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 84 | CRAWKWebView *view = viewRegistry[reactTag]; 85 | if (![view isKindOfClass:[CRAWKWebView class]]) { 86 | RCTLogError(@"Invalid view returned from registry, expecting CRAWKWebView, got: %@", view); 87 | } else { 88 | [view goBack]; 89 | } 90 | }]; 91 | } 92 | 93 | RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag) 94 | { 95 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 96 | CRAWKWebView *view = viewRegistry[reactTag]; 97 | if (![view isKindOfClass:[CRAWKWebView class]]) { 98 | RCTLogError(@"Invalid view returned from registry, expecting CRAWKWebView, got: %@", view); 99 | } else { 100 | [view goForward]; 101 | } 102 | }]; 103 | } 104 | 105 | RCT_EXPORT_METHOD(canGoBack:(nonnull NSNumber *)reactTag 106 | resolver:(RCTPromiseResolveBlock)resolve 107 | rejecter:(RCTPromiseRejectBlock)reject) 108 | { 109 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 110 | CRAWKWebView *view = viewRegistry[reactTag]; 111 | 112 | resolve([NSNumber numberWithBool:[view canGoBack]]); 113 | }]; 114 | } 115 | 116 | RCT_EXPORT_METHOD(canGoForward:(nonnull NSNumber *)reactTag 117 | resolver:(RCTPromiseResolveBlock)resolve 118 | rejecter:(RCTPromiseRejectBlock)reject) 119 | { 120 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 121 | CRAWKWebView *view = viewRegistry[reactTag]; 122 | 123 | resolve([NSNumber numberWithBool:[view canGoForward]]); 124 | }]; 125 | } 126 | 127 | RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag) 128 | { 129 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 130 | CRAWKWebView *view = viewRegistry[reactTag]; 131 | if (![view isKindOfClass:[CRAWKWebView class]]) { 132 | RCTLogError(@"Invalid view returned from registry, expecting CRAWKWebView, got: %@", view); 133 | } else { 134 | [view reload]; 135 | } 136 | }]; 137 | } 138 | 139 | RCT_EXPORT_METHOD(stopLoading:(nonnull NSNumber *)reactTag) 140 | { 141 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 142 | CRAWKWebView *view = viewRegistry[reactTag]; 143 | if (![view isKindOfClass:[CRAWKWebView class]]) { 144 | RCTLogError(@"Invalid view returned from registry, expecting CRAWKWebView, got: %@", view); 145 | } else { 146 | [view stopLoading]; 147 | } 148 | }]; 149 | } 150 | 151 | RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)message) 152 | { 153 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 154 | CRAWKWebView *view = viewRegistry[reactTag]; 155 | if (![view isKindOfClass:[CRAWKWebView class]]) { 156 | RCTLogError(@"Invalid view returned from registry, expecting CRAWKWebView, got: %@", view); 157 | } else { 158 | [view postMessage:message]; 159 | } 160 | }]; 161 | } 162 | 163 | RCT_EXPORT_METHOD(evaluateJavaScript:(nonnull NSNumber *)reactTag 164 | js:(NSString *)js 165 | resolver:(RCTPromiseResolveBlock)resolve 166 | rejecter:(RCTPromiseRejectBlock)reject) 167 | { 168 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { 169 | CRAWKWebView *view = viewRegistry[reactTag]; 170 | if (![view isKindOfClass:[CRAWKWebView class]]) { 171 | RCTLogError(@"Invalid view returned from registry, expecting CRAWKWebView, got: %@", view); 172 | } else { 173 | [view evaluateJavaScript:js completionHandler:^(id result, NSError *error) { 174 | if (error) { 175 | reject(@"js_error", @"Error occurred while evaluating Javascript", error); 176 | } else { 177 | resolve(result); 178 | } 179 | }]; 180 | } 181 | }]; 182 | } 183 | 184 | #pragma mark - Exported synchronous methods 185 | 186 | - (BOOL)webView:(__unused CRAWKWebView *)webView 187 | shouldStartLoadForRequest:(NSMutableDictionary *)request 188 | withCallback:(RCTDirectEventBlock)callback 189 | { 190 | _shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()]; 191 | _shouldStartLoad = YES; 192 | request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition); 193 | callback(request); 194 | 195 | // Block the main thread for a maximum of 250ms until the JS thread returns 196 | if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) { 197 | BOOL returnValue = _shouldStartLoad; 198 | [_shouldStartLoadLock unlock]; 199 | _shouldStartLoadLock = nil; 200 | return returnValue; 201 | } else { 202 | RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES"); 203 | return YES; 204 | } 205 | } 206 | 207 | RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier) 208 | { 209 | if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) { 210 | _shouldStartLoad = result; 211 | [_shouldStartLoadLock unlockWithCondition:0]; 212 | } else { 213 | RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: " 214 | "got %zd, expected %zd", lockIdentifier, _shouldStartLoadLock.condition); 215 | } 216 | } 217 | 218 | @end 219 | -------------------------------------------------------------------------------- /ios/RCTWKWebView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 097457AB1D2A457C000D9368 /* CRAWKWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 097457A91D2A457C000D9368 /* CRAWKWebViewManager.m */; }; 11 | 097457AE1D2A4595000D9368 /* CRAWKWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 097457AD1D2A4595000D9368 /* CRAWKWebView.m */; }; 12 | 097457AF1D2AF4E0000D9368 /* CRAWKWebView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 097457AC1D2A4595000D9368 /* CRAWKWebView.h */; }; 13 | 097457B01D2AF4E0000D9368 /* CRAWKWebViewManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 097457A81D2A457C000D9368 /* CRAWKWebViewManager.h */; }; 14 | 3E609CF61EAA815D00187C8C /* WeakScriptMessageDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E609CF51EAA815D00187C8C /* WeakScriptMessageDelegate.m */; }; 15 | E683F3D72080F3400005F1F5 /* WKProcessPool+SharedProcessPool.m in Sources */ = {isa = PBXBuildFile; fileRef = E683F3D62080F3400005F1F5 /* WKProcessPool+SharedProcessPool.m */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 097457981D2A440A000D9368 /* CopyFiles */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = "include/$(PRODUCT_NAME)"; 23 | dstSubfolderSpec = 16; 24 | files = ( 25 | 097457AF1D2AF4E0000D9368 /* CRAWKWebView.h in CopyFiles */, 26 | 097457B01D2AF4E0000D9368 /* CRAWKWebViewManager.h in CopyFiles */, 27 | ); 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 0974579A1D2A440A000D9368 /* libRCTWKWebView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTWKWebView.a; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 097457A81D2A457C000D9368 /* CRAWKWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRAWKWebViewManager.h; sourceTree = ""; }; 35 | 097457A91D2A457C000D9368 /* CRAWKWebViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = CRAWKWebViewManager.m; sourceTree = ""; tabWidth = 2; }; 36 | 097457AC1D2A4595000D9368 /* CRAWKWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRAWKWebView.h; sourceTree = ""; }; 37 | 097457AD1D2A4595000D9368 /* CRAWKWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = CRAWKWebView.m; sourceTree = ""; tabWidth = 2; }; 38 | 3E609CF41EAA815D00187C8C /* WeakScriptMessageDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakScriptMessageDelegate.h; sourceTree = ""; }; 39 | 3E609CF51EAA815D00187C8C /* WeakScriptMessageDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WeakScriptMessageDelegate.m; sourceTree = ""; }; 40 | E683F3D32080F2E10005F1F5 /* WKProcessPool+SharedProcessPool.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKProcessPool+SharedProcessPool.h"; sourceTree = ""; }; 41 | E683F3D62080F3400005F1F5 /* WKProcessPool+SharedProcessPool.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKProcessPool+SharedProcessPool.m"; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 097457971D2A440A000D9368 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXFrameworksBuildPhase section */ 53 | 54 | /* Begin PBXGroup section */ 55 | 097457911D2A440A000D9368 = { 56 | isa = PBXGroup; 57 | children = ( 58 | 0974579C1D2A440A000D9368 /* RCTWKWebView */, 59 | 0974579B1D2A440A000D9368 /* Products */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | 0974579B1D2A440A000D9368 /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 0974579A1D2A440A000D9368 /* libRCTWKWebView.a */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 0974579C1D2A440A000D9368 /* RCTWKWebView */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 097457AC1D2A4595000D9368 /* CRAWKWebView.h */, 75 | 097457AD1D2A4595000D9368 /* CRAWKWebView.m */, 76 | 097457A81D2A457C000D9368 /* CRAWKWebViewManager.h */, 77 | 097457A91D2A457C000D9368 /* CRAWKWebViewManager.m */, 78 | 3E609CF41EAA815D00187C8C /* WeakScriptMessageDelegate.h */, 79 | 3E609CF51EAA815D00187C8C /* WeakScriptMessageDelegate.m */, 80 | E683F3D32080F2E10005F1F5 /* WKProcessPool+SharedProcessPool.h */, 81 | E683F3D62080F3400005F1F5 /* WKProcessPool+SharedProcessPool.m */, 82 | ); 83 | path = RCTWKWebView; 84 | sourceTree = ""; 85 | }; 86 | /* End PBXGroup section */ 87 | 88 | /* Begin PBXNativeTarget section */ 89 | 097457991D2A440A000D9368 /* RCTWKWebView */ = { 90 | isa = PBXNativeTarget; 91 | buildConfigurationList = 097457A31D2A440A000D9368 /* Build configuration list for PBXNativeTarget "RCTWKWebView" */; 92 | buildPhases = ( 93 | 097457961D2A440A000D9368 /* Sources */, 94 | 097457971D2A440A000D9368 /* Frameworks */, 95 | 097457981D2A440A000D9368 /* CopyFiles */, 96 | ); 97 | buildRules = ( 98 | ); 99 | dependencies = ( 100 | ); 101 | name = RCTWKWebView; 102 | productName = RCTWKWebView; 103 | productReference = 0974579A1D2A440A000D9368 /* libRCTWKWebView.a */; 104 | productType = "com.apple.product-type.library.static"; 105 | }; 106 | /* End PBXNativeTarget section */ 107 | 108 | /* Begin PBXProject section */ 109 | 097457921D2A440A000D9368 /* Project object */ = { 110 | isa = PBXProject; 111 | attributes = { 112 | LastUpgradeCheck = 0920; 113 | TargetAttributes = { 114 | 097457991D2A440A000D9368 = { 115 | CreatedOnToolsVersion = 7.3.1; 116 | }; 117 | }; 118 | }; 119 | buildConfigurationList = 097457951D2A440A000D9368 /* Build configuration list for PBXProject "RCTWKWebView" */; 120 | compatibilityVersion = "Xcode 3.2"; 121 | developmentRegion = English; 122 | hasScannedForEncodings = 0; 123 | knownRegions = ( 124 | en, 125 | ); 126 | mainGroup = 097457911D2A440A000D9368; 127 | productRefGroup = 0974579B1D2A440A000D9368 /* Products */; 128 | projectDirPath = ""; 129 | projectRoot = ""; 130 | targets = ( 131 | 097457991D2A440A000D9368 /* RCTWKWebView */, 132 | ); 133 | }; 134 | /* End PBXProject section */ 135 | 136 | /* Begin PBXSourcesBuildPhase section */ 137 | 097457961D2A440A000D9368 /* Sources */ = { 138 | isa = PBXSourcesBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | 097457AB1D2A457C000D9368 /* CRAWKWebViewManager.m in Sources */, 142 | 3E609CF61EAA815D00187C8C /* WeakScriptMessageDelegate.m in Sources */, 143 | E683F3D72080F3400005F1F5 /* WKProcessPool+SharedProcessPool.m in Sources */, 144 | 097457AE1D2A4595000D9368 /* CRAWKWebView.m in Sources */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | /* End PBXSourcesBuildPhase section */ 149 | 150 | /* Begin XCBuildConfiguration section */ 151 | 097457A11D2A440A000D9368 /* Debug */ = { 152 | isa = XCBuildConfiguration; 153 | buildSettings = { 154 | ALWAYS_SEARCH_USER_PATHS = NO; 155 | CLANG_ANALYZER_NONNULL = YES; 156 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 157 | CLANG_CXX_LIBRARY = "libc++"; 158 | CLANG_ENABLE_MODULES = YES; 159 | CLANG_ENABLE_OBJC_ARC = YES; 160 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 161 | CLANG_WARN_BOOL_CONVERSION = YES; 162 | CLANG_WARN_COMMA = YES; 163 | CLANG_WARN_CONSTANT_CONVERSION = YES; 164 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 165 | CLANG_WARN_EMPTY_BODY = YES; 166 | CLANG_WARN_ENUM_CONVERSION = YES; 167 | CLANG_WARN_INFINITE_RECURSION = YES; 168 | CLANG_WARN_INT_CONVERSION = YES; 169 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 170 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 171 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 172 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 173 | CLANG_WARN_STRICT_PROTOTYPES = YES; 174 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 175 | CLANG_WARN_UNREACHABLE_CODE = YES; 176 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 177 | COPY_PHASE_STRIP = NO; 178 | DEBUG_INFORMATION_FORMAT = dwarf; 179 | ENABLE_STRICT_OBJC_MSGSEND = YES; 180 | ENABLE_TESTABILITY = YES; 181 | GCC_C_LANGUAGE_STANDARD = gnu99; 182 | GCC_DYNAMIC_NO_PIC = NO; 183 | GCC_NO_COMMON_BLOCKS = YES; 184 | GCC_OPTIMIZATION_LEVEL = 0; 185 | GCC_PREPROCESSOR_DEFINITIONS = ( 186 | "DEBUG=1", 187 | "$(inherited)", 188 | ); 189 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 190 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 191 | GCC_WARN_UNDECLARED_SELECTOR = YES; 192 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 193 | GCC_WARN_UNUSED_FUNCTION = YES; 194 | GCC_WARN_UNUSED_VARIABLE = YES; 195 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 196 | MTL_ENABLE_DEBUG_INFO = YES; 197 | ONLY_ACTIVE_ARCH = YES; 198 | SDKROOT = iphoneos; 199 | }; 200 | name = Debug; 201 | }; 202 | 097457A21D2A440A000D9368 /* Release */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | ALWAYS_SEARCH_USER_PATHS = NO; 206 | CLANG_ANALYZER_NONNULL = YES; 207 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 208 | CLANG_CXX_LIBRARY = "libc++"; 209 | CLANG_ENABLE_MODULES = YES; 210 | CLANG_ENABLE_OBJC_ARC = YES; 211 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 212 | CLANG_WARN_BOOL_CONVERSION = YES; 213 | CLANG_WARN_COMMA = YES; 214 | CLANG_WARN_CONSTANT_CONVERSION = YES; 215 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 216 | CLANG_WARN_EMPTY_BODY = YES; 217 | CLANG_WARN_ENUM_CONVERSION = YES; 218 | CLANG_WARN_INFINITE_RECURSION = YES; 219 | CLANG_WARN_INT_CONVERSION = YES; 220 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 221 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 222 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 223 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 224 | CLANG_WARN_STRICT_PROTOTYPES = YES; 225 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 226 | CLANG_WARN_UNREACHABLE_CODE = YES; 227 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 228 | COPY_PHASE_STRIP = NO; 229 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 230 | ENABLE_NS_ASSERTIONS = NO; 231 | ENABLE_STRICT_OBJC_MSGSEND = YES; 232 | GCC_C_LANGUAGE_STANDARD = gnu99; 233 | GCC_NO_COMMON_BLOCKS = YES; 234 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 235 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 236 | GCC_WARN_UNDECLARED_SELECTOR = YES; 237 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 238 | GCC_WARN_UNUSED_FUNCTION = YES; 239 | GCC_WARN_UNUSED_VARIABLE = YES; 240 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 241 | MTL_ENABLE_DEBUG_INFO = NO; 242 | SDKROOT = iphoneos; 243 | VALIDATE_PRODUCT = YES; 244 | }; 245 | name = Release; 246 | }; 247 | 097457A41D2A440A000D9368 /* Debug */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | HEADER_SEARCH_PATHS = ( 251 | "$(SRCROOT)/../../React/**", 252 | "$(inherited)", 253 | "$(SRCROOT)/node_modules/react-native/React/**", 254 | "$(SRCROOT)/../react-native/React/**", 255 | "$(SRCROOT)/../../../node_modules/react-native/React/**", 256 | ); 257 | OTHER_LDFLAGS = "-ObjC"; 258 | PRODUCT_NAME = "$(TARGET_NAME)"; 259 | SKIP_INSTALL = YES; 260 | }; 261 | name = Debug; 262 | }; 263 | 097457A51D2A440A000D9368 /* Release */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | HEADER_SEARCH_PATHS = ( 267 | "$(SRCROOT)/../../React/**", 268 | "$(inherited)", 269 | "$(SRCROOT)/node_modules/react-native/React/**", 270 | "$(SRCROOT)/../react-native/React/**", 271 | "$(SRCROOT)/../../../node_modules/react-native/React/**", 272 | ); 273 | OTHER_LDFLAGS = "-ObjC"; 274 | PRODUCT_NAME = "$(TARGET_NAME)"; 275 | SKIP_INSTALL = YES; 276 | }; 277 | name = Release; 278 | }; 279 | /* End XCBuildConfiguration section */ 280 | 281 | /* Begin XCConfigurationList section */ 282 | 097457951D2A440A000D9368 /* Build configuration list for PBXProject "RCTWKWebView" */ = { 283 | isa = XCConfigurationList; 284 | buildConfigurations = ( 285 | 097457A11D2A440A000D9368 /* Debug */, 286 | 097457A21D2A440A000D9368 /* Release */, 287 | ); 288 | defaultConfigurationIsVisible = 0; 289 | defaultConfigurationName = Release; 290 | }; 291 | 097457A31D2A440A000D9368 /* Build configuration list for PBXNativeTarget "RCTWKWebView" */ = { 292 | isa = XCConfigurationList; 293 | buildConfigurations = ( 294 | 097457A41D2A440A000D9368 /* Debug */, 295 | 097457A51D2A440A000D9368 /* Release */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Release; 299 | }; 300 | /* End XCConfigurationList section */ 301 | }; 302 | rootObject = 097457921D2A440A000D9368 /* Project object */; 303 | } 304 | -------------------------------------------------------------------------------- /WKWebView.ios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | import PropTypes from 'prop-types'; 5 | import ReactNative, { 6 | requireNativeComponent, 7 | EdgeInsetsPropType, 8 | StyleSheet, 9 | UIManager, 10 | View, 11 | ViewPropTypes, 12 | NativeModules, 13 | Text, 14 | ActivityIndicator 15 | } from 'react-native'; 16 | 17 | import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'; 18 | import deprecatedPropType from 'react-native/Libraries/Utilities/deprecatedPropType'; 19 | import invariant from 'fbjs/lib/invariant'; 20 | import keyMirror from 'fbjs/lib/keyMirror'; 21 | const WKWebViewManager = NativeModules.CRAWKWebViewManager; 22 | 23 | var BGWASH = 'rgba(255,255,255,0.8)'; 24 | 25 | const WebViewState = keyMirror({ 26 | IDLE: null, 27 | LOADING: null, 28 | ERROR: null, 29 | }); 30 | 31 | const NavigationType = keyMirror({ 32 | click: true, 33 | formsubmit: true, 34 | backforward: true, 35 | reload: true, 36 | formresubmit: true, 37 | other: true, 38 | }); 39 | 40 | const JSNavigationScheme = 'react-js-navigation'; 41 | 42 | type ErrorEvent = { 43 | domain: any; 44 | code: any; 45 | description: any; 46 | } 47 | 48 | type Event = Object; 49 | 50 | const defaultRenderLoading = () => ( 51 | 52 | 53 | 54 | ); 55 | const defaultRenderError = (errorDomain, errorCode, errorDesc) => ( 56 | 57 | 58 | Error loading page 59 | 60 | 61 | {'Domain: ' + errorDomain} 62 | 63 | 64 | {'Error Code: ' + errorCode} 65 | 66 | 67 | {'Description: ' + errorDesc} 68 | 69 | 70 | ); 71 | 72 | /** 73 | * Renders a native WebView. 74 | */ 75 | 76 | class WKWebView extends React.Component { 77 | static JSNavigationScheme = JSNavigationScheme; 78 | static NavigationType = NavigationType; 79 | 80 | static propTypes = { 81 | ...ViewPropTypes, 82 | 83 | html: deprecatedPropType( 84 | PropTypes.string, 85 | 'Use the `source` prop instead.' 86 | ), 87 | 88 | url: deprecatedPropType( 89 | PropTypes.string, 90 | 'Use the `source` prop instead.' 91 | ), 92 | 93 | /** 94 | * Loads static html or a uri (with optional headers) in the WebView. 95 | */ 96 | source: PropTypes.oneOfType([ 97 | PropTypes.shape({ 98 | /* 99 | * The URI to load in the WebView. Can be a local or remote file. 100 | */ 101 | uri: PropTypes.string, 102 | /* 103 | * The HTTP Method to use. Defaults to GET if not specified. 104 | * NOTE: On Android, only GET and POST are supported. 105 | */ 106 | method: PropTypes.string, 107 | /* 108 | * Additional HTTP headers to send with the request. 109 | * NOTE: On Android, this can only be used with GET requests. 110 | */ 111 | headers: PropTypes.object, 112 | /* 113 | * The HTTP body to send with the request. This must be a valid 114 | * UTF-8 string, and will be sent exactly as specified, with no 115 | * additional encoding (e.g. URL-escaping or base64) applied. 116 | * NOTE: On Android, this can only be used with POST requests. 117 | */ 118 | body: PropTypes.string, 119 | }), 120 | PropTypes.shape({ 121 | /* 122 | * A static HTML page to display in the WebView. 123 | */ 124 | html: PropTypes.string, 125 | /* 126 | * The base URL to be used for any relative links in the HTML. 127 | */ 128 | baseUrl: PropTypes.string, 129 | }), 130 | /* 131 | * Used internally by packager. 132 | */ 133 | PropTypes.number, 134 | ]), 135 | 136 | /** 137 | * This property specifies how the safe area insets are used to modify the 138 | * content area of the scroll view. The default value of this property is 139 | * "never". Available on iOS 11 and later. 140 | */ 141 | contentInsetAdjustmentBehavior: PropTypes.oneOf([ 142 | 'automatic', 143 | 'scrollableAxes', 144 | 'never', // default 145 | 'always', 146 | ]), 147 | 148 | /** 149 | * Function that returns a view to show if there's an error. 150 | */ 151 | renderError: PropTypes.func, // view to show if there's an error 152 | /** 153 | * Function that returns a loading indicator. 154 | */ 155 | renderLoading: PropTypes.func, 156 | /** 157 | * Invoked when load finish 158 | */ 159 | onLoad: PropTypes.func, 160 | /** 161 | * Invoked when load either succeeds or fails 162 | */ 163 | onLoadEnd: PropTypes.func, 164 | /** 165 | * Invoked on load start 166 | */ 167 | onLoadStart: PropTypes.func, 168 | /** 169 | * Invoked when load fails 170 | */ 171 | onError: PropTypes.func, 172 | /** 173 | * Report the progress 174 | */ 175 | onProgress: PropTypes.func, 176 | /** 177 | * A function that is invoked when the webview calls `window.postMessage`. 178 | * Setting this property will inject a `postMessage` global into your 179 | * webview, but will still call pre-existing values of `postMessage`. 180 | * 181 | * `window.postMessage` accepts one argument, `data`, which will be 182 | * available on the event object, `event.nativeEvent.data`. `data` 183 | * must be a string. 184 | */ 185 | onMessage: PropTypes.func, 186 | /** 187 | * Receive scroll events from view 188 | */ 189 | onScroll: PropTypes.func, 190 | /** 191 | * A callback to get response headers, http status code and http localized status code. 192 | */ 193 | onNavigationResponse: PropTypes.func, 194 | /** 195 | * @platform ios 196 | */ 197 | bounces: PropTypes.bool, 198 | scrollEnabled: PropTypes.bool, 199 | allowsBackForwardNavigationGestures: PropTypes.bool, 200 | automaticallyAdjustContentInsets: PropTypes.bool, 201 | contentInset: EdgeInsetsPropType, 202 | onNavigationStateChange: PropTypes.func, 203 | scalesPageToFit: PropTypes.bool, 204 | startInLoadingState: PropTypes.bool, 205 | style: ViewPropTypes.style, 206 | /** 207 | * If false injectJavaScript will run both main frame and iframe 208 | * @platform ios 209 | */ 210 | injectJavaScriptForMainFrameOnly: PropTypes.bool, 211 | /** 212 | * If false injectedJavaScript will run both main frame and iframe 213 | * @platform ios 214 | */ 215 | injectedJavaScriptForMainFrameOnly: PropTypes.bool, 216 | /** 217 | * Function that accepts a string that will be passed to the WebView and executed immediately as JavaScript. 218 | */ 219 | injectJavaScript: PropTypes.string, 220 | /** 221 | * Sets the JS to be injected when the webpage loads. 222 | */ 223 | injectedJavaScript: PropTypes.string, 224 | /** 225 | * Allows custom handling of any webview requests by a JS handler. Return true 226 | * or false from this method to continue loading the request. 227 | * @platform ios 228 | */ 229 | onShouldStartLoadWithRequest: PropTypes.func, 230 | /** 231 | * Copies cookies from sharedHTTPCookieStorage when calling loadRequest. 232 | * Set this to true to emulate behavior of WebView component. 233 | */ 234 | sendCookies: PropTypes.bool, 235 | /** 236 | * If set to true, target="_blank" or window.open will be opened in WebView, instead 237 | * of new window. Default is false to be backward compatible. 238 | */ 239 | openNewWindowInWebView: PropTypes.bool, 240 | /** 241 | * Hide the accessory view when the keyboard is open. Default is false to be 242 | * backward compatible. 243 | */ 244 | hideKeyboardAccessoryView: PropTypes.bool, 245 | /** 246 | * Enable the keyboard to display when focusing an input in a webview programatically 247 | */ 248 | keyboardDisplayRequiresUserAction: PropTypes.bool, 249 | /** 250 | * A Boolean value that determines whether pressing on a link displays a preview of the destination for the link. This props is available on devices that support 3D Touch. In iOS 10 and later, the default value is true; before that, the default value is false. 251 | */ 252 | allowsLinkPreview: PropTypes.bool, 253 | /** 254 | * Sets the customized user agent by using of the WKWebView 255 | */ 256 | customUserAgent: PropTypes.string, 257 | userAgent: PropTypes.string, 258 | /** 259 | * A Boolean value that determines whether paging is enabled for the scroll view. 260 | */ 261 | pagingEnabled: PropTypes.bool, 262 | /** 263 | * A Boolean value that sets whether diagonal scrolling is allowed. 264 | */ 265 | directionalLockEnabled: PropTypes.bool, 266 | /* 267 | * The manner in which the keyboard is dismissed when a drag begins in the 268 | * scroll view. 269 | */ 270 | keyboardDismissMode: PropTypes.oneOf([ 271 | 'none', // Default 272 | 'on-drag', 273 | 'interactive', // iOS only 274 | ]), 275 | }; 276 | 277 | state = { 278 | viewState: WebViewState.IDLE, 279 | lastErrorEvent: (null: ?ErrorEvent), 280 | startInLoadingState: true, 281 | }; 282 | 283 | componentWillMount() { 284 | if (this.props.startInLoadingState) { 285 | this.setState({ viewState: WebViewState.LOADING }); 286 | } 287 | } 288 | 289 | render() { 290 | let otherView = null; 291 | 292 | if (this.state.viewState === WebViewState.LOADING) { 293 | otherView = (this.props.renderLoading || defaultRenderLoading)(); 294 | } else if (this.state.viewState === WebViewState.ERROR) { 295 | const errorEvent = this.state.lastErrorEvent; 296 | invariant( 297 | errorEvent != null, 298 | 'lastErrorEvent expected to be non-null' 299 | ); 300 | otherView = (this.props.renderError || defaultRenderError)( 301 | errorEvent.domain, 302 | errorEvent.code, 303 | errorEvent.description 304 | ); 305 | } else if (this.state.viewState !== WebViewState.IDLE) { 306 | console.error( 307 | 'CRAWKWebView invalid state encountered: ' + this.state.loading 308 | ); 309 | } 310 | 311 | const webViewStyles = [styles.container, styles.webView, this.props.style]; 312 | if (this.state.viewState === WebViewState.LOADING || 313 | this.state.viewState === WebViewState.ERROR) { 314 | // if we're in either LOADING or ERROR states, don't show the webView 315 | webViewStyles.push(styles.hidden); 316 | } 317 | 318 | const onShouldStartLoadWithRequest = this.props.onShouldStartLoadWithRequest && ((event: Event) => { 319 | const shouldStart = this.props.onShouldStartLoadWithRequest && 320 | this.props.onShouldStartLoadWithRequest(event.nativeEvent); 321 | WKWebViewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier); 322 | }); 323 | 324 | let source = this.props.source; 325 | if (this.props.source && typeof this.props.source === 'object') { 326 | source = Object.assign({}, this.props.source, { 327 | sendCookies: this.props.sendCookies, 328 | customUserAgent: this.props.customUserAgent || this.props.userAgent 329 | }); 330 | 331 | if (this.props.html) { 332 | source.html = this.props.html; 333 | } else if (this.props.url) { 334 | source.uri = this.props.url; 335 | } 336 | } 337 | 338 | const messagingEnabled = typeof this.props.onMessage === 'function'; 339 | 340 | const webView = 341 | { this.webview = ref; }} 343 | key="webViewKey" 344 | style={webViewStyles} 345 | contentInsetAdjustmentBehavior={this.props.contentInsetAdjustmentBehavior} 346 | source={resolveAssetSource(source)} 347 | injectJavaScriptForMainFrameOnly={this.props.injectJavaScriptForMainFrameOnly} 348 | injectedJavaScriptForMainFrameOnly={this.props.injectedJavaScriptForMainFrameOnly} 349 | injectJavaScript={this.props.injectJavaScript} 350 | injectedJavaScript={this.props.injectedJavaScript} 351 | bounces={this.props.bounces} 352 | scrollEnabled={this.props.scrollEnabled} 353 | contentInset={this.props.contentInset} 354 | allowsBackForwardNavigationGestures={this.props.allowsBackForwardNavigationGestures} 355 | automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets} 356 | openNewWindowInWebView={this.props.openNewWindowInWebView} 357 | hideKeyboardAccessoryView={this.props.hideKeyboardAccessoryView} 358 | keyboardDisplayRequiresUserAction={this.props.keyboardDisplayRequiresUserAction} 359 | allowsLinkPreview={this.props.allowsLinkPreview} 360 | onLoadingStart={this._onLoadingStart} 361 | onLoadingFinish={this._onLoadingFinish} 362 | onLoadingError={this._onLoadingError} 363 | messagingEnabled={messagingEnabled} 364 | onProgress={this._onProgress} 365 | onMessage={this._onMessage} 366 | onScroll={this._onScroll} 367 | onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} 368 | pagingEnabled={this.props.pagingEnabled} 369 | directionalLockEnabled={this.props.directionalLockEnabled} 370 | onNavigationResponse={this._onNavigationResponse} 371 | keyboardDismissMode={this.props.keyboardDismissMode} 372 | />; 373 | 374 | return ( 375 | 376 | {webView} 377 | {otherView} 378 | 379 | ); 380 | } 381 | 382 | /** 383 | * Go forward one page in the webview's history. 384 | */ 385 | goForward = () => { 386 | UIManager.dispatchViewManagerCommand( 387 | this.getWebViewHandle(), 388 | this.getCRAWKWebView().Commands.goForward, 389 | null 390 | ); 391 | }; 392 | 393 | /** 394 | * Go back one page in the webview's history. 395 | */ 396 | goBack = () => { 397 | UIManager.dispatchViewManagerCommand( 398 | this.getWebViewHandle(), 399 | this.getCRAWKWebView().Commands.goBack, 400 | null 401 | ); 402 | }; 403 | 404 | /** 405 | * Indicating whether there is a back item in the back-forward list that can be navigated to 406 | */ 407 | canGoBack = () => { 408 | return WKWebViewManager.canGoBack(this.getWebViewHandle()); 409 | }; 410 | 411 | /** 412 | * Indicating whether there is a forward item in the back-forward list that can be navigated to 413 | */ 414 | canGoForward = () => { 415 | return WKWebViewManager.canGoForward(this.getWebViewHandle()); 416 | }; 417 | 418 | /** 419 | * Reloads the current page. 420 | */ 421 | reload = () => { 422 | this.setState({ viewState: WebViewState.LOADING }); 423 | UIManager.dispatchViewManagerCommand( 424 | this.getWebViewHandle(), 425 | this.getCRAWKWebView().Commands.reload, 426 | null 427 | ); 428 | }; 429 | 430 | /** 431 | * Stop loading the current page. 432 | */ 433 | stopLoading = () => { 434 | UIManager.dispatchViewManagerCommand( 435 | this.getWebViewHandle(), 436 | this.getCRAWKWebView().Commands.stopLoading, 437 | null 438 | ) 439 | }; 440 | 441 | /** 442 | * Posts a message to the web view, which will emit a `message` event. 443 | * Accepts one argument, `data`, which must be a string. 444 | * 445 | * In your webview, you'll need to something like the following. 446 | * 447 | * ```js 448 | * document.addEventListener('message', e => { document.title = e.data; }); 449 | * ``` 450 | */ 451 | postMessage = (data) => { 452 | UIManager.dispatchViewManagerCommand( 453 | this.getWebViewHandle(), 454 | this.getCRAWKWebView().Commands.postMessage, 455 | [String(data)] 456 | ); 457 | }; 458 | 459 | evaluateJavaScript = (js) => { 460 | return WKWebViewManager.evaluateJavaScript(this.getWebViewHandle(), js); 461 | }; 462 | 463 | /** 464 | * We return an event with a bunch of fields including: 465 | * url, title, loading, canGoBack, canGoForward 466 | */ 467 | _updateNavigationState = (event: Event) => { 468 | if (this.props.onNavigationStateChange) { 469 | this.props.onNavigationStateChange(event.nativeEvent); 470 | } 471 | }; 472 | 473 | getCRAWKWebView = () => { 474 | return ( 475 | UIManager.getViewManagerConfig ? 476 | UIManager.getViewManagerConfig('CRAWKWebView') : 477 | UIManager.CRAWKWebView 478 | ); 479 | }; 480 | 481 | /** 482 | * Returns the native webview node. 483 | */ 484 | getWebViewHandle = (): any => { 485 | return ReactNative.findNodeHandle(this.webview); 486 | }; 487 | 488 | _onLoadingStart = (event: Event) => { 489 | const onLoadStart = this.props.onLoadStart; 490 | onLoadStart && onLoadStart(event); 491 | this._updateNavigationState(event); 492 | }; 493 | 494 | _onLoadingError = (event: Event) => { 495 | event.persist(); // persist this event because we need to store it 496 | const { onError, onLoadEnd } = this.props; 497 | onError && onError(event); 498 | onLoadEnd && onLoadEnd(event); 499 | console.warn('Encountered an error loading page', event.nativeEvent); 500 | 501 | this.setState({ 502 | lastErrorEvent: event.nativeEvent, 503 | viewState: WebViewState.ERROR 504 | }); 505 | }; 506 | 507 | _onLoadingFinish = (event: Event) => { 508 | const { onLoad, onLoadEnd } = this.props; 509 | onLoad && onLoad(event); 510 | onLoadEnd && onLoadEnd(event); 511 | this.setState({ 512 | viewState: WebViewState.IDLE, 513 | }); 514 | this._updateNavigationState(event); 515 | }; 516 | 517 | _onProgress = (event: Event) => { 518 | const onProgress = this.props.onProgress; 519 | onProgress && onProgress(event.nativeEvent.progress); 520 | }; 521 | 522 | _onMessage = (event: Event) => { 523 | var { onMessage } = this.props; 524 | onMessage && onMessage(event); 525 | }; 526 | 527 | _onScroll = (event: Event) => { 528 | const onScroll = this.props.onScroll; 529 | onScroll && onScroll(event.nativeEvent); 530 | }; 531 | 532 | _onNavigationResponse = (event: Event) => { 533 | const { onNavigationResponse } = this.props; 534 | onNavigationResponse && onNavigationResponse(event) 535 | } 536 | } 537 | 538 | const CRAWKWebView = requireNativeComponent('CRAWKWebView', WKWebView, { 539 | nativeOnly: { 540 | onLoadingStart: true, 541 | onLoadingError: true, 542 | onLoadingFinish: true, 543 | onMessage: true, 544 | messagingEnabled: PropTypes.bool, 545 | } 546 | }); 547 | 548 | const styles = StyleSheet.create({ 549 | container: { 550 | flex: 1, 551 | }, 552 | errorContainer: { 553 | flex: 1, 554 | justifyContent: 'center', 555 | alignItems: 'center', 556 | backgroundColor: BGWASH, 557 | }, 558 | errorText: { 559 | fontSize: 14, 560 | textAlign: 'center', 561 | marginBottom: 2, 562 | }, 563 | errorTextTitle: { 564 | fontSize: 15, 565 | fontWeight: '500', 566 | marginBottom: 10, 567 | }, 568 | hidden: { 569 | height: 0, 570 | flex: 0, // disable 'flex:1' when hiding a View 571 | }, 572 | loadingView: { 573 | backgroundColor: BGWASH, 574 | flex: 1, 575 | justifyContent: 'center', 576 | alignItems: 'center', 577 | height: 100, 578 | }, 579 | webView: { 580 | backgroundColor: '#ffffff', 581 | } 582 | }); 583 | 584 | export default WKWebView; 585 | -------------------------------------------------------------------------------- /ios/RCTWKWebView/CRAWKWebView.m: -------------------------------------------------------------------------------- 1 | #import "CRAWKWebView.h" 2 | 3 | #import "WeakScriptMessageDelegate.h" 4 | 5 | #import 6 | 7 | #import 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | #import 16 | 17 | // runtime trick to remove WKWebView keyboard default toolbar 18 | // see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279 19 | @interface _SwizzleHelperWK : NSObject @end 20 | @implementation _SwizzleHelperWK 21 | -(id)inputAccessoryView 22 | { 23 | return nil; 24 | } 25 | @end 26 | 27 | @interface CRAWKWebView () 28 | 29 | @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart; 30 | @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish; 31 | @property (nonatomic, copy) RCTDirectEventBlock onLoadingError; 32 | @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest; 33 | @property (nonatomic, copy) RCTDirectEventBlock onProgress; 34 | @property (nonatomic, copy) RCTDirectEventBlock onMessage; 35 | @property (nonatomic, copy) RCTDirectEventBlock onScroll; 36 | @property (nonatomic, copy) RCTDirectEventBlock onNavigationResponse; 37 | @property (assign) BOOL sendCookies; 38 | @property (nonatomic, strong) WKUserScript *atStartScript; 39 | @property (nonatomic, strong) WKUserScript *atEndScript; 40 | 41 | @end 42 | 43 | @implementation CRAWKWebView 44 | { 45 | WKWebView *_webView; 46 | BOOL _injectJavaScriptForMainFrameOnly; 47 | BOOL _injectedJavaScriptForMainFrameOnly; 48 | NSString *_injectJavaScript; 49 | NSString *_injectedJavaScript; 50 | } 51 | 52 | - (instancetype)initWithFrame:(CGRect)frame 53 | { 54 | return self = [super initWithFrame:frame]; 55 | } 56 | 57 | RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) 58 | 59 | - (instancetype)initWithProcessPool:(WKProcessPool *)processPool 60 | { 61 | if(self = [self initWithFrame:CGRectZero]) 62 | { 63 | super.backgroundColor = [UIColor clearColor]; 64 | _automaticallyAdjustContentInsets = YES; 65 | _contentInset = UIEdgeInsetsZero; 66 | 67 | WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init]; 68 | config.processPool = processPool; 69 | WKUserContentController* userController = [[WKUserContentController alloc]init]; 70 | [userController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"reactNative"]; 71 | config.userContentController = userController; 72 | 73 | _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration:config]; 74 | _webView.UIDelegate = self; 75 | _webView.navigationDelegate = self; 76 | _webView.scrollView.delegate = self; 77 | 78 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ 79 | // `contentInsetAdjustmentBehavior` is only available since iOS 11. 80 | // We set the default behavior to "never" so that iOS 81 | // doesn't do weird things to UIScrollView insets automatically 82 | // and keeps it as an opt-in behavior. 83 | if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { 84 | _webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 85 | } 86 | #endif 87 | [self setupPostMessageScript]; 88 | [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; 89 | [self addSubview:_webView]; 90 | } 91 | return self; 92 | } 93 | 94 | - (void)setInjectJavaScript:(NSString *)injectJavaScript { 95 | _injectJavaScript = injectJavaScript; 96 | self.atStartScript = [[WKUserScript alloc] initWithSource:injectJavaScript 97 | injectionTime:WKUserScriptInjectionTimeAtDocumentStart 98 | forMainFrameOnly:_injectJavaScriptForMainFrameOnly]; 99 | [self resetupScripts]; 100 | } 101 | 102 | - (void)setInjectedJavaScript:(NSString *)script { 103 | _injectedJavaScript = script; 104 | self.atEndScript = [[WKUserScript alloc] initWithSource:script 105 | injectionTime:WKUserScriptInjectionTimeAtDocumentEnd 106 | forMainFrameOnly:_injectedJavaScriptForMainFrameOnly]; 107 | [self resetupScripts]; 108 | } 109 | 110 | - (void)setInjectedJavaScriptForMainFrameOnly:(BOOL)injectedJavaScriptForMainFrameOnly { 111 | _injectedJavaScriptForMainFrameOnly = injectedJavaScriptForMainFrameOnly; 112 | if (_injectedJavaScript != nil) { 113 | [self setInjectedJavaScript:_injectedJavaScript]; 114 | } 115 | } 116 | 117 | - (void)setInjectJavaScriptForMainFrameOnly:(BOOL)injectJavaScriptForMainFrameOnly { 118 | _injectJavaScriptForMainFrameOnly = injectJavaScriptForMainFrameOnly; 119 | if (_injectJavaScript != nil) { 120 | [self setInjectJavaScript:_injectJavaScript]; 121 | } 122 | } 123 | 124 | - (void)setMessagingEnabled:(BOOL)messagingEnabled { 125 | _messagingEnabled = messagingEnabled; 126 | [self setupPostMessageScript]; 127 | } 128 | 129 | - (void)resetupScripts { 130 | [_webView.configuration.userContentController removeAllUserScripts]; 131 | [self setupPostMessageScript]; 132 | if (self.atStartScript) { 133 | [_webView.configuration.userContentController addUserScript:self.atStartScript]; 134 | } 135 | if (self.atEndScript) { 136 | [_webView.configuration.userContentController addUserScript:self.atEndScript]; 137 | } 138 | } 139 | 140 | - (void)setupPostMessageScript { 141 | if (_messagingEnabled) { 142 | NSString *source = @"window.originalPostMessage = window.postMessage;" 143 | "window.postMessage = function(message, targetOrigin, transfer) {" 144 | "window.webkit.messageHandlers.reactNative.postMessage(message);" 145 | "if (typeof targetOrigin !== 'undefined') {" 146 | "window.originalPostMessage(message, targetOrigin, transfer);" 147 | "}" 148 | "};"; 149 | WKUserScript *script = [[WKUserScript alloc] initWithSource:source 150 | injectionTime:WKUserScriptInjectionTimeAtDocumentStart 151 | forMainFrameOnly:_injectedJavaScriptForMainFrameOnly]; 152 | [_webView.configuration.userContentController addUserScript:script]; 153 | } 154 | } 155 | 156 | - (void)loadRequest:(NSURLRequest *)request 157 | { 158 | if (request.URL && _sendCookies) { 159 | NSDictionary *cookies = [NSHTTPCookie requestHeaderFieldsWithCookies:[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL]]; 160 | if ([cookies objectForKey:@"Cookie"]) { 161 | NSMutableURLRequest *mutableRequest = request.mutableCopy; 162 | [mutableRequest addValue:cookies[@"Cookie"] forHTTPHeaderField:@"Cookie"]; 163 | request = mutableRequest; 164 | } 165 | } 166 | 167 | [_webView loadRequest:request]; 168 | } 169 | 170 | -(void)setAllowsLinkPreview:(BOOL)allowsLinkPreview 171 | { 172 | if ([_webView respondsToSelector:@selector(allowsLinkPreview)]) { 173 | _webView.allowsLinkPreview = allowsLinkPreview; 174 | } 175 | } 176 | 177 | -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView 178 | { 179 | if (!hideKeyboardAccessoryView) { 180 | return; 181 | } 182 | 183 | UIView* subview; 184 | for (UIView* view in _webView.scrollView.subviews) { 185 | if([[view.class description] hasPrefix:@"WKContent"]) 186 | subview = view; 187 | } 188 | 189 | if(subview == nil) return; 190 | 191 | NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelperWK", subview.class.superclass]; 192 | Class newClass = NSClassFromString(name); 193 | 194 | if(newClass == nil) 195 | { 196 | newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0); 197 | if(!newClass) return; 198 | 199 | Method method = class_getInstanceMethod([_SwizzleHelperWK class], @selector(inputAccessoryView)); 200 | class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method)); 201 | 202 | objc_registerClassPair(newClass); 203 | } 204 | 205 | object_setClass(subview, newClass); 206 | } 207 | 208 | // https://github.com/Telerik-Verified-Plugins/WKWebView/commit/04e8296adeb61f289f9c698045c19b62d080c7e3 209 | // https://stackoverflow.com/a/48623286/3297914 210 | -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAction 211 | { 212 | if (!keyboardDisplayRequiresUserAction) { 213 | Class class = NSClassFromString(@"WKContentView"); 214 | NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0}; 215 | 216 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) { 217 | SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:"); 218 | Method method = class_getInstanceMethod(class, selector); 219 | IMP original = method_getImplementation(method); 220 | IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) { 221 | ((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4); 222 | }); 223 | method_setImplementation(method, override); 224 | } else { 225 | SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:"); 226 | Method method = class_getInstanceMethod(class, selector); 227 | IMP original = method_getImplementation(method); 228 | IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3) { 229 | ((void (*)(id, SEL, void*, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3); 230 | }); 231 | method_setImplementation(method, override); 232 | } 233 | } 234 | } 235 | 236 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ 237 | - (void)setContentInsetAdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior 238 | { 239 | // `contentInsetAdjustmentBehavior` is available since iOS 11. 240 | if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { 241 | CGPoint contentOffset = _webView.scrollView.contentOffset; 242 | _webView.scrollView.contentInsetAdjustmentBehavior = behavior; 243 | _webView.scrollView.contentOffset = contentOffset; 244 | } 245 | } 246 | #endif 247 | 248 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 249 | { 250 | if (_onMessage) { 251 | NSMutableDictionary *event = [self baseEvent]; 252 | [event addEntriesFromDictionary: @{ 253 | @"data": message.body, 254 | @"name": message.name 255 | }]; 256 | _onMessage(event); 257 | } 258 | } 259 | 260 | - (void)goForward 261 | { 262 | [_webView goForward]; 263 | } 264 | 265 | - (void)evaluateJavaScript:(NSString *)javaScriptString 266 | completionHandler:(void (^)(id, NSError *error))completionHandler 267 | { 268 | [_webView evaluateJavaScript:javaScriptString completionHandler:completionHandler]; 269 | } 270 | 271 | - (void)postMessage:(NSString *)message 272 | { 273 | NSDictionary *eventInitDict = @{ 274 | @"data": message, 275 | }; 276 | NSString *source = [NSString 277 | stringWithFormat:@"document.dispatchEvent(new MessageEvent('message', %@));", 278 | RCTJSONStringify(eventInitDict, NULL) 279 | ]; 280 | [_webView evaluateJavaScript:source completionHandler:nil]; 281 | } 282 | 283 | 284 | - (void)goBack 285 | { 286 | [_webView goBack]; 287 | } 288 | 289 | - (BOOL)canGoBack 290 | { 291 | return [_webView canGoBack]; 292 | } 293 | 294 | - (BOOL)canGoForward 295 | { 296 | return [_webView canGoForward]; 297 | } 298 | 299 | - (void)reload 300 | { 301 | [_webView reload]; 302 | } 303 | 304 | - (void)stopLoading 305 | { 306 | [_webView stopLoading]; 307 | } 308 | 309 | - (void)setSource:(NSDictionary *)source 310 | { 311 | if (![_source isEqualToDictionary:source]) { 312 | _source = [source copy]; 313 | _sendCookies = [source[@"sendCookies"] boolValue]; 314 | if ([source[@"customUserAgent"] length] != 0 && [_webView respondsToSelector:@selector(setCustomUserAgent:)]) { 315 | [_webView setCustomUserAgent:source[@"customUserAgent"]]; 316 | } 317 | 318 | // Allow loading local files: 319 | // 320 | // Only works for iOS 9+. So iOS 8 will simply ignore those two values 321 | NSString *file = [RCTConvert NSString:source[@"file"]]; 322 | NSString *allowingReadAccessToURL = [RCTConvert NSString:source[@"allowingReadAccessToURL"]]; 323 | 324 | if (file && [_webView respondsToSelector:@selector(loadFileURL:allowingReadAccessToURL:)]) { 325 | NSURL *fileURL = [RCTConvert NSURL:file]; 326 | NSURL *baseURL = [RCTConvert NSURL:allowingReadAccessToURL]; 327 | [_webView loadFileURL:fileURL allowingReadAccessToURL:baseURL]; 328 | return; 329 | } 330 | 331 | // Check for a static html source first 332 | NSString *html = [RCTConvert NSString:source[@"html"]]; 333 | if (html) { 334 | NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]]; 335 | if (!baseURL) { 336 | baseURL = [NSURL URLWithString:@"about:blank"]; 337 | } 338 | [_webView loadHTMLString:html baseURL:baseURL]; 339 | return; 340 | } 341 | 342 | NSURLRequest *request = [RCTConvert NSURLRequest:source]; 343 | // Because of the way React works, as pages redirect, we actually end up 344 | // passing the redirect urls back here, so we ignore them if trying to load 345 | // the same url. We'll expose a call to 'reload' to allow a user to load 346 | // the existing page. 347 | if ([request.URL isEqual:_webView.URL]) { 348 | return; 349 | } 350 | if (!request.URL) { 351 | // Clear the webview 352 | [_webView loadHTMLString:@"" baseURL:nil]; 353 | return; 354 | } 355 | [self loadRequest:request]; 356 | } 357 | } 358 | 359 | - (void)layoutSubviews 360 | { 361 | [super layoutSubviews]; 362 | _webView.frame = self.bounds; 363 | } 364 | 365 | - (void)setContentInset:(UIEdgeInsets)contentInset 366 | { 367 | _contentInset = contentInset; 368 | [RCTView autoAdjustInsetsForView:self 369 | withScrollView:_webView.scrollView 370 | updateOffset:NO]; 371 | } 372 | 373 | - (void)setBackgroundColor:(UIColor *)backgroundColor 374 | { 375 | CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor); 376 | self.opaque = _webView.opaque = _webView.scrollView.opaque = (alpha == 1.0); 377 | _webView.backgroundColor = _webView.scrollView.backgroundColor = backgroundColor; 378 | } 379 | 380 | - (UIColor *)backgroundColor 381 | { 382 | return _webView.backgroundColor; 383 | } 384 | 385 | - (NSMutableDictionary *)baseEvent 386 | { 387 | NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary:@{ 388 | @"url": _webView.URL.absoluteString ?: @"", 389 | @"loading" : @(_webView.loading), 390 | @"title": _webView.title, 391 | @"canGoBack": @(_webView.canGoBack), 392 | @"canGoForward" : @(_webView.canGoForward), 393 | }]; 394 | 395 | return event; 396 | } 397 | 398 | - (void)refreshContentInset 399 | { 400 | [RCTView autoAdjustInsetsForView:self 401 | withScrollView:_webView.scrollView 402 | updateOffset:YES]; 403 | } 404 | 405 | - (void)observeValueForKeyPath:(NSString *)keyPath 406 | ofObject:(id)object 407 | change:(NSDictionary *)change 408 | context:(void *)context 409 | { 410 | if ([keyPath isEqualToString:@"estimatedProgress"]) { 411 | if (!_onProgress) { 412 | return; 413 | } 414 | _onProgress(@{@"progress": [change objectForKey:NSKeyValueChangeNewKey]}); 415 | } 416 | } 417 | 418 | - (void)dealloc 419 | { 420 | [_webView removeObserver:self forKeyPath:@"estimatedProgress"]; 421 | _webView.navigationDelegate = nil; 422 | _webView.UIDelegate = nil; 423 | _webView.scrollView.delegate = nil; 424 | } 425 | 426 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView 427 | { 428 | if (!scrollView.scrollEnabled) { 429 | scrollView.bounds = _webView.bounds; 430 | return; 431 | } 432 | NSDictionary *event = @{ 433 | @"contentOffset": @{ 434 | @"x": @(scrollView.contentOffset.x), 435 | @"y": @(scrollView.contentOffset.y) 436 | }, 437 | @"contentInset": @{ 438 | @"top": @(scrollView.contentInset.top), 439 | @"left": @(scrollView.contentInset.left), 440 | @"bottom": @(scrollView.contentInset.bottom), 441 | @"right": @(scrollView.contentInset.right) 442 | }, 443 | @"contentSize": @{ 444 | @"width": @(scrollView.contentSize.width), 445 | @"height": @(scrollView.contentSize.height) 446 | }, 447 | @"layoutMeasurement": @{ 448 | @"width": @(scrollView.frame.size.width), 449 | @"height": @(scrollView.frame.size.height) 450 | }, 451 | @"zoomScale": @(scrollView.zoomScale ?: 1), 452 | }; 453 | _onScroll(event); 454 | } 455 | 456 | #pragma mark - WKNavigationDelegate methods 457 | 458 | #if DEBUG 459 | - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { 460 | NSURLCredential * credential = [[NSURLCredential alloc] initWithTrust:[challenge protectionSpace].serverTrust]; 461 | completionHandler(NSURLSessionAuthChallengeUseCredential, credential); 462 | } 463 | #endif 464 | 465 | - (void)webView:(__unused WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler 466 | { 467 | UIApplication *app = [UIApplication sharedApplication]; 468 | NSURLRequest *request = navigationAction.request; 469 | NSURL* url = request.URL; 470 | NSString* scheme = url.scheme; 471 | 472 | BOOL isJSNavigation = [scheme isEqualToString:RCTJSNavigationScheme]; 473 | 474 | // handle mailto and tel schemes 475 | if ([scheme isEqualToString:@"mailto"] || [scheme isEqualToString:@"tel"]) { 476 | if ([app canOpenURL:url]) { 477 | [app openURL:url]; 478 | decisionHandler(WKNavigationActionPolicyCancel); 479 | return; 480 | } 481 | } 482 | 483 | // skip this for the JS Navigation handler 484 | if (!isJSNavigation && _onShouldStartLoadWithRequest) { 485 | NSMutableDictionary *event = [self baseEvent]; 486 | [event addEntriesFromDictionary: @{ 487 | @"url": (request.URL).absoluteString, 488 | @"navigationType": @(navigationAction.navigationType) 489 | }]; 490 | if (![self.delegate webView:self 491 | shouldStartLoadForRequest:event 492 | withCallback:_onShouldStartLoadWithRequest]) { 493 | return decisionHandler(WKNavigationActionPolicyCancel); 494 | } 495 | } 496 | 497 | if (_onLoadingStart) { 498 | // We have this check to filter out iframe requests and whatnot 499 | BOOL isTopFrame = [url isEqual:request.mainDocumentURL]; 500 | if (isTopFrame) { 501 | NSMutableDictionary *event = [self baseEvent]; 502 | [event addEntriesFromDictionary: @{ 503 | @"url": url.absoluteString, 504 | @"navigationType": @(navigationAction.navigationType) 505 | }]; 506 | _onLoadingStart(event); 507 | } 508 | } 509 | 510 | if (isJSNavigation) { 511 | decisionHandler(WKNavigationActionPolicyCancel); 512 | } 513 | else { 514 | decisionHandler(WKNavigationActionPolicyAllow); 515 | } 516 | } 517 | 518 | - (void)webView:(__unused WKWebView *)webView didFailProvisionalNavigation:(__unused WKNavigation *)navigation withError:(NSError *)error 519 | { 520 | if (_onLoadingError) { 521 | if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) { 522 | // NSURLErrorCancelled is reported when a page has a redirect OR if you load 523 | // a new URL in the WebView before the previous one came back. We can just 524 | // ignore these since they aren't real errors. 525 | // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os 526 | return; 527 | } 528 | 529 | NSMutableDictionary *event = [self baseEvent]; 530 | [event addEntriesFromDictionary:@{ 531 | @"domain": error.domain, 532 | @"code": @(error.code), 533 | @"description": error.localizedDescription, 534 | }]; 535 | _onLoadingError(event); 536 | } 537 | } 538 | 539 | - (void)webView:(WKWebView *)webView didFinishNavigation:(__unused WKNavigation *)navigation 540 | { 541 | // we only need the final 'finishLoad' call so only fire the event when we're actually done loading. 542 | if (_onLoadingFinish && !webView.loading && ![webView.URL.absoluteString isEqualToString:@"about:blank"]) { 543 | _onLoadingFinish([self baseEvent]); 544 | } 545 | } 546 | 547 | #pragma mark - WKUIDelegate 548 | 549 | - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { 550 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 551 | 552 | [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Close", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { 553 | completionHandler(); 554 | }]]; 555 | UIViewController *presentingController = RCTPresentedViewController(); 556 | [presentingController presentViewController:alertController animated:YES completion:nil]; 557 | } 558 | 559 | - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler { 560 | 561 | // TODO We have to think message to confirm "YES" 562 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 563 | [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 564 | completionHandler(YES); 565 | }]]; 566 | [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { 567 | completionHandler(NO); 568 | }]]; 569 | UIViewController *presentingController = RCTPresentedViewController(); 570 | [presentingController presentViewController:alertController animated:YES completion:nil]; 571 | } 572 | 573 | - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler { 574 | 575 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:nil preferredStyle:UIAlertControllerStyleAlert]; 576 | [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { 577 | textField.text = defaultText; 578 | }]; 579 | 580 | [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 581 | NSString *input = ((UITextField *)alertController.textFields.firstObject).text; 582 | completionHandler(input); 583 | }]]; 584 | 585 | [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { 586 | completionHandler(nil); 587 | }]]; 588 | UIViewController *presentingController = RCTPresentedViewController(); 589 | [presentingController presentViewController:alertController animated:YES completion:nil]; 590 | } 591 | 592 | - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 593 | { 594 | NSString *scheme = navigationAction.request.URL.scheme; 595 | if ((navigationAction.targetFrame.isMainFrame || _openNewWindowInWebView) && ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])) { 596 | [webView loadRequest:navigationAction.request]; 597 | } else { 598 | UIApplication *app = [UIApplication sharedApplication]; 599 | NSURL *url = navigationAction.request.URL; 600 | if ([app canOpenURL:url]) { 601 | [app openURL:url]; 602 | } 603 | } 604 | return nil; 605 | } 606 | 607 | - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView 608 | { 609 | RCTLogWarn(@"Webview Process Terminated"); 610 | } 611 | 612 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { 613 | if (_onNavigationResponse) { 614 | NSDictionary *headers = @{}; 615 | NSInteger statusCode = 200; 616 | if([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]){ 617 | headers = ((NSHTTPURLResponse *)navigationResponse.response).allHeaderFields; 618 | statusCode = ((NSHTTPURLResponse *)navigationResponse.response).statusCode; 619 | } 620 | 621 | NSMutableDictionary *event = [self baseEvent]; 622 | [event addEntriesFromDictionary:@{ 623 | @"headers": headers, 624 | @"status": [NSHTTPURLResponse localizedStringForStatusCode:statusCode], 625 | @"statusCode": @(statusCode), 626 | }]; 627 | _onNavigationResponse(event); 628 | } 629 | 630 | decisionHandler(WKNavigationResponsePolicyAllow); 631 | } 632 | 633 | @end 634 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 11 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; 12 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; 13 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 14 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 15 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 16 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; 17 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; 18 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 19 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 20 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 21 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 22 | 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 23 | 49934B3E1F15D9BB00BB8FD1 /* libRCTWKWebView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 49944C941F14C5DF005CAC91 /* libRCTWKWebView.a */; }; 24 | 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; 25 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; 32 | proxyType = 2; 33 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 34 | remoteInfo = RCTActionSheet; 35 | }; 36 | 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; 39 | proxyType = 2; 40 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 41 | remoteInfo = RCTGeolocation; 42 | }; 43 | 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; 46 | proxyType = 2; 47 | remoteGlobalIDString = 58B5115D1A9E6B3D00147676; 48 | remoteInfo = RCTImage; 49 | }; 50 | 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; 53 | proxyType = 2; 54 | remoteGlobalIDString = 58B511DB1A9E6C8500147676; 55 | remoteInfo = RCTNetwork; 56 | }; 57 | 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { 58 | isa = PBXContainerItemProxy; 59 | containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; 60 | proxyType = 2; 61 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; 62 | remoteInfo = RCTVibration; 63 | }; 64 | 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { 65 | isa = PBXContainerItemProxy; 66 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; 67 | proxyType = 2; 68 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 69 | remoteInfo = RCTSettings; 70 | }; 71 | 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { 72 | isa = PBXContainerItemProxy; 73 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 74 | proxyType = 2; 75 | remoteGlobalIDString = 3C86DF461ADF2C930047B81A; 76 | remoteInfo = RCTWebSocket; 77 | }; 78 | 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { 79 | isa = PBXContainerItemProxy; 80 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 81 | proxyType = 2; 82 | remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; 83 | remoteInfo = React; 84 | }; 85 | 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = { 86 | isa = PBXContainerItemProxy; 87 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; 88 | proxyType = 2; 89 | remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; 90 | remoteInfo = "RCTImage-tvOS"; 91 | }; 92 | 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = { 93 | isa = PBXContainerItemProxy; 94 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; 95 | proxyType = 2; 96 | remoteGlobalIDString = 2D2A28471D9B043800D4039D; 97 | remoteInfo = "RCTLinking-tvOS"; 98 | }; 99 | 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = { 100 | isa = PBXContainerItemProxy; 101 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; 102 | proxyType = 2; 103 | remoteGlobalIDString = 2D2A28541D9B044C00D4039D; 104 | remoteInfo = "RCTNetwork-tvOS"; 105 | }; 106 | 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = { 107 | isa = PBXContainerItemProxy; 108 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; 109 | proxyType = 2; 110 | remoteGlobalIDString = 2D2A28611D9B046600D4039D; 111 | remoteInfo = "RCTSettings-tvOS"; 112 | }; 113 | 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = { 114 | isa = PBXContainerItemProxy; 115 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; 116 | proxyType = 2; 117 | remoteGlobalIDString = 2D2A287B1D9B048500D4039D; 118 | remoteInfo = "RCTText-tvOS"; 119 | }; 120 | 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = { 121 | isa = PBXContainerItemProxy; 122 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 123 | proxyType = 2; 124 | remoteGlobalIDString = 2D2A28881D9B049200D4039D; 125 | remoteInfo = "RCTWebSocket-tvOS"; 126 | }; 127 | 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = { 128 | isa = PBXContainerItemProxy; 129 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 130 | proxyType = 2; 131 | remoteGlobalIDString = 2D2A28131D9B038B00D4039D; 132 | remoteInfo = "React-tvOS"; 133 | }; 134 | 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = { 135 | isa = PBXContainerItemProxy; 136 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 137 | proxyType = 2; 138 | remoteGlobalIDString = 3D3C059A1DE3340900C268FA; 139 | remoteInfo = yoga; 140 | }; 141 | 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = { 142 | isa = PBXContainerItemProxy; 143 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 144 | proxyType = 2; 145 | remoteGlobalIDString = 3D3C06751DE3340C00C268FA; 146 | remoteInfo = "yoga-tvOS"; 147 | }; 148 | 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = { 149 | isa = PBXContainerItemProxy; 150 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 151 | proxyType = 2; 152 | remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; 153 | remoteInfo = cxxreact; 154 | }; 155 | 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = { 156 | isa = PBXContainerItemProxy; 157 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 158 | proxyType = 2; 159 | remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; 160 | remoteInfo = "cxxreact-tvOS"; 161 | }; 162 | 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = { 163 | isa = PBXContainerItemProxy; 164 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 165 | proxyType = 2; 166 | remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; 167 | remoteInfo = jschelpers; 168 | }; 169 | 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = { 170 | isa = PBXContainerItemProxy; 171 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 172 | proxyType = 2; 173 | remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; 174 | remoteInfo = "jschelpers-tvOS"; 175 | }; 176 | 49944C931F14C5DF005CAC91 /* PBXContainerItemProxy */ = { 177 | isa = PBXContainerItemProxy; 178 | containerPortal = 49944C8F1F14C5DF005CAC91 /* RCTWKWebView.xcodeproj */; 179 | proxyType = 2; 180 | remoteGlobalIDString = 0974579A1D2A440A000D9368; 181 | remoteInfo = RCTWKWebView; 182 | }; 183 | 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { 184 | isa = PBXContainerItemProxy; 185 | containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; 186 | proxyType = 2; 187 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 188 | remoteInfo = RCTAnimation; 189 | }; 190 | 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { 191 | isa = PBXContainerItemProxy; 192 | containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; 193 | proxyType = 2; 194 | remoteGlobalIDString = 2D2A28201D9B03D100D4039D; 195 | remoteInfo = "RCTAnimation-tvOS"; 196 | }; 197 | 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { 198 | isa = PBXContainerItemProxy; 199 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; 200 | proxyType = 2; 201 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 202 | remoteInfo = RCTLinking; 203 | }; 204 | 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { 205 | isa = PBXContainerItemProxy; 206 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; 207 | proxyType = 2; 208 | remoteGlobalIDString = 58B5119B1A9E6C1200147676; 209 | remoteInfo = RCTText; 210 | }; 211 | E69E1C17203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 212 | isa = PBXContainerItemProxy; 213 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 214 | proxyType = 2; 215 | remoteGlobalIDString = 3DBE0D001F3B181A0099AA32; 216 | remoteInfo = fishhook; 217 | }; 218 | E69E1C19203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 219 | isa = PBXContainerItemProxy; 220 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 221 | proxyType = 2; 222 | remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32; 223 | remoteInfo = "fishhook-tvOS"; 224 | }; 225 | E69E1C2C203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 226 | isa = PBXContainerItemProxy; 227 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 228 | proxyType = 2; 229 | remoteGlobalIDString = EBF21BDC1FC498900052F4D5; 230 | remoteInfo = jsinspector; 231 | }; 232 | E69E1C2E203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 233 | isa = PBXContainerItemProxy; 234 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 235 | proxyType = 2; 236 | remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5; 237 | remoteInfo = "jsinspector-tvOS"; 238 | }; 239 | E69E1C30203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 240 | isa = PBXContainerItemProxy; 241 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 242 | proxyType = 2; 243 | remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7; 244 | remoteInfo = "third-party"; 245 | }; 246 | E69E1C32203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 247 | isa = PBXContainerItemProxy; 248 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 249 | proxyType = 2; 250 | remoteGlobalIDString = 3D383D3C1EBD27B6005632C8; 251 | remoteInfo = "third-party-tvOS"; 252 | }; 253 | E69E1C34203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 254 | isa = PBXContainerItemProxy; 255 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 256 | proxyType = 2; 257 | remoteGlobalIDString = 139D7E881E25C6D100323FB7; 258 | remoteInfo = "double-conversion"; 259 | }; 260 | E69E1C36203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 261 | isa = PBXContainerItemProxy; 262 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 263 | proxyType = 2; 264 | remoteGlobalIDString = 3D383D621EBD27B9005632C8; 265 | remoteInfo = "double-conversion-tvOS"; 266 | }; 267 | E69E1C38203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 268 | isa = PBXContainerItemProxy; 269 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 270 | proxyType = 2; 271 | remoteGlobalIDString = 9936F3131F5F2E4B0010BF04; 272 | remoteInfo = privatedata; 273 | }; 274 | E69E1C3A203B3E9A00A2D664 /* PBXContainerItemProxy */ = { 275 | isa = PBXContainerItemProxy; 276 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 277 | proxyType = 2; 278 | remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04; 279 | remoteInfo = "privatedata-tvOS"; 280 | }; 281 | /* End PBXContainerItemProxy section */ 282 | 283 | /* Begin PBXFileReference section */ 284 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; 285 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; 286 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; 287 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; 288 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; 289 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; 290 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; 291 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; 292 | 13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 293 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = ""; }; 294 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/AppDelegate.m; sourceTree = ""; }; 295 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 296 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = ""; }; 297 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; }; 298 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = ""; }; 299 | 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; 300 | 49944C8F1F14C5DF005CAC91 /* RCTWKWebView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWKWebView.xcodeproj; path = "../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView.xcodeproj"; sourceTree = ""; }; 301 | 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; 302 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 303 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; 304 | /* End PBXFileReference section */ 305 | 306 | /* Begin PBXFrameworksBuildPhase section */ 307 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { 308 | isa = PBXFrameworksBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | 49934B3E1F15D9BB00BB8FD1 /* libRCTWKWebView.a in Frameworks */, 312 | 146834051AC3E58100842450 /* libReact.a in Frameworks */, 313 | 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, 314 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 315 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, 316 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, 317 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, 318 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, 319 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, 320 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 321 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 322 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | /* End PBXFrameworksBuildPhase section */ 327 | 328 | /* Begin PBXGroup section */ 329 | 00C302A81ABCB8CE00DB3ED1 /* Products */ = { 330 | isa = PBXGroup; 331 | children = ( 332 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, 333 | ); 334 | name = Products; 335 | sourceTree = ""; 336 | }; 337 | 00C302B61ABCB90400DB3ED1 /* Products */ = { 338 | isa = PBXGroup; 339 | children = ( 340 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, 341 | ); 342 | name = Products; 343 | sourceTree = ""; 344 | }; 345 | 00C302BC1ABCB91800DB3ED1 /* Products */ = { 346 | isa = PBXGroup; 347 | children = ( 348 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, 349 | 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */, 350 | ); 351 | name = Products; 352 | sourceTree = ""; 353 | }; 354 | 00C302D41ABCB9D200DB3ED1 /* Products */ = { 355 | isa = PBXGroup; 356 | children = ( 357 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, 358 | 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */, 359 | ); 360 | name = Products; 361 | sourceTree = ""; 362 | }; 363 | 00C302E01ABCB9EE00DB3ED1 /* Products */ = { 364 | isa = PBXGroup; 365 | children = ( 366 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, 367 | ); 368 | name = Products; 369 | sourceTree = ""; 370 | }; 371 | 139105B71AF99BAD00B5F7CC /* Products */ = { 372 | isa = PBXGroup; 373 | children = ( 374 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, 375 | 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */, 376 | ); 377 | name = Products; 378 | sourceTree = ""; 379 | }; 380 | 139FDEE71B06529A00C62182 /* Products */ = { 381 | isa = PBXGroup; 382 | children = ( 383 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, 384 | 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */, 385 | E69E1C18203B3E9A00A2D664 /* libfishhook.a */, 386 | E69E1C1A203B3E9A00A2D664 /* libfishhook-tvOS.a */, 387 | ); 388 | name = Products; 389 | sourceTree = ""; 390 | }; 391 | 13B07FAE1A68108700A75B9A /* example */ = { 392 | isa = PBXGroup; 393 | children = ( 394 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 395 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 396 | 13B07FB01A68108700A75B9A /* AppDelegate.m */, 397 | 13B07FB51A68108700A75B9A /* Images.xcassets */, 398 | 13B07FB61A68108700A75B9A /* Info.plist */, 399 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 400 | 13B07FB71A68108700A75B9A /* main.m */, 401 | ); 402 | name = example; 403 | sourceTree = ""; 404 | }; 405 | 146834001AC3E56700842450 /* Products */ = { 406 | isa = PBXGroup; 407 | children = ( 408 | 146834041AC3E56700842450 /* libReact.a */, 409 | 3DAD3EA31DF850E9000B6D8A /* libReact.a */, 410 | 3DAD3EA51DF850E9000B6D8A /* libyoga.a */, 411 | 3DAD3EA71DF850E9000B6D8A /* libyoga.a */, 412 | 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */, 413 | 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */, 414 | 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */, 415 | 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */, 416 | E69E1C2D203B3E9A00A2D664 /* libjsinspector.a */, 417 | E69E1C2F203B3E9A00A2D664 /* libjsinspector-tvOS.a */, 418 | E69E1C31203B3E9A00A2D664 /* libthird-party.a */, 419 | E69E1C33203B3E9A00A2D664 /* libthird-party.a */, 420 | E69E1C35203B3E9A00A2D664 /* libdouble-conversion.a */, 421 | E69E1C37203B3E9A00A2D664 /* libdouble-conversion.a */, 422 | E69E1C39203B3E9A00A2D664 /* libprivatedata.a */, 423 | E69E1C3B203B3E9A00A2D664 /* libprivatedata-tvOS.a */, 424 | ); 425 | name = Products; 426 | sourceTree = ""; 427 | }; 428 | 49944C901F14C5DF005CAC91 /* Products */ = { 429 | isa = PBXGroup; 430 | children = ( 431 | 49944C941F14C5DF005CAC91 /* libRCTWKWebView.a */, 432 | ); 433 | name = Products; 434 | sourceTree = ""; 435 | }; 436 | 5E91572E1DD0AC6500FF2AA8 /* Products */ = { 437 | isa = PBXGroup; 438 | children = ( 439 | 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */, 440 | 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */, 441 | ); 442 | name = Products; 443 | sourceTree = ""; 444 | }; 445 | 78C398B11ACF4ADC00677621 /* Products */ = { 446 | isa = PBXGroup; 447 | children = ( 448 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, 449 | 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */, 450 | ); 451 | name = Products; 452 | sourceTree = ""; 453 | }; 454 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = { 455 | isa = PBXGroup; 456 | children = ( 457 | 49944C8F1F14C5DF005CAC91 /* RCTWKWebView.xcodeproj */, 458 | 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */, 459 | 146833FF1AC3E56700842450 /* React.xcodeproj */, 460 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 461 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, 462 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, 463 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, 464 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, 465 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, 466 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 467 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, 468 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, 469 | ); 470 | name = Libraries; 471 | sourceTree = ""; 472 | }; 473 | 832341B11AAA6A8300B99B32 /* Products */ = { 474 | isa = PBXGroup; 475 | children = ( 476 | 832341B51AAA6A8300B99B32 /* libRCTText.a */, 477 | 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */, 478 | ); 479 | name = Products; 480 | sourceTree = ""; 481 | }; 482 | 83CBB9F61A601CBA00E9B192 = { 483 | isa = PBXGroup; 484 | children = ( 485 | 13B07FAE1A68108700A75B9A /* example */, 486 | 832341AE1AAA6A7D00B99B32 /* Libraries */, 487 | 83CBBA001A601CBA00E9B192 /* Products */, 488 | ); 489 | indentWidth = 2; 490 | sourceTree = ""; 491 | tabWidth = 2; 492 | }; 493 | 83CBBA001A601CBA00E9B192 /* Products */ = { 494 | isa = PBXGroup; 495 | children = ( 496 | 13B07F961A680F5B00A75B9A /* example.app */, 497 | ); 498 | name = Products; 499 | sourceTree = ""; 500 | }; 501 | /* End PBXGroup section */ 502 | 503 | /* Begin PBXNativeTarget section */ 504 | 13B07F861A680F5B00A75B9A /* example */ = { 505 | isa = PBXNativeTarget; 506 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; 507 | buildPhases = ( 508 | 13B07F871A680F5B00A75B9A /* Sources */, 509 | 13B07F8C1A680F5B00A75B9A /* Frameworks */, 510 | 13B07F8E1A680F5B00A75B9A /* Resources */, 511 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 512 | ); 513 | buildRules = ( 514 | ); 515 | dependencies = ( 516 | ); 517 | name = example; 518 | productName = "Hello World"; 519 | productReference = 13B07F961A680F5B00A75B9A /* example.app */; 520 | productType = "com.apple.product-type.application"; 521 | }; 522 | /* End PBXNativeTarget section */ 523 | 524 | /* Begin PBXProject section */ 525 | 83CBB9F71A601CBA00E9B192 /* Project object */ = { 526 | isa = PBXProject; 527 | attributes = { 528 | LastUpgradeCheck = 0820; 529 | ORGANIZATIONNAME = Facebook; 530 | TargetAttributes = { 531 | 13B07F861A680F5B00A75B9A = { 532 | DevelopmentTeam = U7CY7GS6FN; 533 | }; 534 | }; 535 | }; 536 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */; 537 | compatibilityVersion = "Xcode 3.2"; 538 | developmentRegion = English; 539 | hasScannedForEncodings = 0; 540 | knownRegions = ( 541 | en, 542 | Base, 543 | ); 544 | mainGroup = 83CBB9F61A601CBA00E9B192; 545 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; 546 | projectDirPath = ""; 547 | projectReferences = ( 548 | { 549 | ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; 550 | ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; 551 | }, 552 | { 553 | ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */; 554 | ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; 555 | }, 556 | { 557 | ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; 558 | ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; 559 | }, 560 | { 561 | ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; 562 | ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; 563 | }, 564 | { 565 | ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; 566 | ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; 567 | }, 568 | { 569 | ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; 570 | ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; 571 | }, 572 | { 573 | ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; 574 | ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; 575 | }, 576 | { 577 | ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; 578 | ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; 579 | }, 580 | { 581 | ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; 582 | ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; 583 | }, 584 | { 585 | ProductGroup = 139FDEE71B06529A00C62182 /* Products */; 586 | ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 587 | }, 588 | { 589 | ProductGroup = 49944C901F14C5DF005CAC91 /* Products */; 590 | ProjectRef = 49944C8F1F14C5DF005CAC91 /* RCTWKWebView.xcodeproj */; 591 | }, 592 | { 593 | ProductGroup = 146834001AC3E56700842450 /* Products */; 594 | ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; 595 | }, 596 | ); 597 | projectRoot = ""; 598 | targets = ( 599 | 13B07F861A680F5B00A75B9A /* example */, 600 | ); 601 | }; 602 | /* End PBXProject section */ 603 | 604 | /* Begin PBXReferenceProxy section */ 605 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { 606 | isa = PBXReferenceProxy; 607 | fileType = archive.ar; 608 | path = libRCTActionSheet.a; 609 | remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; 610 | sourceTree = BUILT_PRODUCTS_DIR; 611 | }; 612 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { 613 | isa = PBXReferenceProxy; 614 | fileType = archive.ar; 615 | path = libRCTGeolocation.a; 616 | remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; 617 | sourceTree = BUILT_PRODUCTS_DIR; 618 | }; 619 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { 620 | isa = PBXReferenceProxy; 621 | fileType = archive.ar; 622 | path = libRCTImage.a; 623 | remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; 624 | sourceTree = BUILT_PRODUCTS_DIR; 625 | }; 626 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { 627 | isa = PBXReferenceProxy; 628 | fileType = archive.ar; 629 | path = libRCTNetwork.a; 630 | remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; 631 | sourceTree = BUILT_PRODUCTS_DIR; 632 | }; 633 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { 634 | isa = PBXReferenceProxy; 635 | fileType = archive.ar; 636 | path = libRCTVibration.a; 637 | remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; 638 | sourceTree = BUILT_PRODUCTS_DIR; 639 | }; 640 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { 641 | isa = PBXReferenceProxy; 642 | fileType = archive.ar; 643 | path = libRCTSettings.a; 644 | remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; 645 | sourceTree = BUILT_PRODUCTS_DIR; 646 | }; 647 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { 648 | isa = PBXReferenceProxy; 649 | fileType = archive.ar; 650 | path = libRCTWebSocket.a; 651 | remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; 652 | sourceTree = BUILT_PRODUCTS_DIR; 653 | }; 654 | 146834041AC3E56700842450 /* libReact.a */ = { 655 | isa = PBXReferenceProxy; 656 | fileType = archive.ar; 657 | path = libReact.a; 658 | remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; 659 | sourceTree = BUILT_PRODUCTS_DIR; 660 | }; 661 | 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = { 662 | isa = PBXReferenceProxy; 663 | fileType = archive.ar; 664 | path = "libRCTImage-tvOS.a"; 665 | remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */; 666 | sourceTree = BUILT_PRODUCTS_DIR; 667 | }; 668 | 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = { 669 | isa = PBXReferenceProxy; 670 | fileType = archive.ar; 671 | path = "libRCTLinking-tvOS.a"; 672 | remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */; 673 | sourceTree = BUILT_PRODUCTS_DIR; 674 | }; 675 | 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = { 676 | isa = PBXReferenceProxy; 677 | fileType = archive.ar; 678 | path = "libRCTNetwork-tvOS.a"; 679 | remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */; 680 | sourceTree = BUILT_PRODUCTS_DIR; 681 | }; 682 | 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = { 683 | isa = PBXReferenceProxy; 684 | fileType = archive.ar; 685 | path = "libRCTSettings-tvOS.a"; 686 | remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */; 687 | sourceTree = BUILT_PRODUCTS_DIR; 688 | }; 689 | 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = { 690 | isa = PBXReferenceProxy; 691 | fileType = archive.ar; 692 | path = "libRCTText-tvOS.a"; 693 | remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */; 694 | sourceTree = BUILT_PRODUCTS_DIR; 695 | }; 696 | 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = { 697 | isa = PBXReferenceProxy; 698 | fileType = archive.ar; 699 | path = "libRCTWebSocket-tvOS.a"; 700 | remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */; 701 | sourceTree = BUILT_PRODUCTS_DIR; 702 | }; 703 | 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = { 704 | isa = PBXReferenceProxy; 705 | fileType = archive.ar; 706 | path = libReact.a; 707 | remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; 708 | sourceTree = BUILT_PRODUCTS_DIR; 709 | }; 710 | 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = { 711 | isa = PBXReferenceProxy; 712 | fileType = archive.ar; 713 | path = libyoga.a; 714 | remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */; 715 | sourceTree = BUILT_PRODUCTS_DIR; 716 | }; 717 | 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = { 718 | isa = PBXReferenceProxy; 719 | fileType = archive.ar; 720 | path = libyoga.a; 721 | remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */; 722 | sourceTree = BUILT_PRODUCTS_DIR; 723 | }; 724 | 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = { 725 | isa = PBXReferenceProxy; 726 | fileType = archive.ar; 727 | path = libcxxreact.a; 728 | remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */; 729 | sourceTree = BUILT_PRODUCTS_DIR; 730 | }; 731 | 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = { 732 | isa = PBXReferenceProxy; 733 | fileType = archive.ar; 734 | path = libcxxreact.a; 735 | remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */; 736 | sourceTree = BUILT_PRODUCTS_DIR; 737 | }; 738 | 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = { 739 | isa = PBXReferenceProxy; 740 | fileType = archive.ar; 741 | path = libjschelpers.a; 742 | remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */; 743 | sourceTree = BUILT_PRODUCTS_DIR; 744 | }; 745 | 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = { 746 | isa = PBXReferenceProxy; 747 | fileType = archive.ar; 748 | path = libjschelpers.a; 749 | remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */; 750 | sourceTree = BUILT_PRODUCTS_DIR; 751 | }; 752 | 49944C941F14C5DF005CAC91 /* libRCTWKWebView.a */ = { 753 | isa = PBXReferenceProxy; 754 | fileType = archive.ar; 755 | path = libRCTWKWebView.a; 756 | remoteRef = 49944C931F14C5DF005CAC91 /* PBXContainerItemProxy */; 757 | sourceTree = BUILT_PRODUCTS_DIR; 758 | }; 759 | 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { 760 | isa = PBXReferenceProxy; 761 | fileType = archive.ar; 762 | path = libRCTAnimation.a; 763 | remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */; 764 | sourceTree = BUILT_PRODUCTS_DIR; 765 | }; 766 | 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { 767 | isa = PBXReferenceProxy; 768 | fileType = archive.ar; 769 | path = libRCTAnimation.a; 770 | remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */; 771 | sourceTree = BUILT_PRODUCTS_DIR; 772 | }; 773 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { 774 | isa = PBXReferenceProxy; 775 | fileType = archive.ar; 776 | path = libRCTLinking.a; 777 | remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; 778 | sourceTree = BUILT_PRODUCTS_DIR; 779 | }; 780 | 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { 781 | isa = PBXReferenceProxy; 782 | fileType = archive.ar; 783 | path = libRCTText.a; 784 | remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; 785 | sourceTree = BUILT_PRODUCTS_DIR; 786 | }; 787 | E69E1C18203B3E9A00A2D664 /* libfishhook.a */ = { 788 | isa = PBXReferenceProxy; 789 | fileType = archive.ar; 790 | path = libfishhook.a; 791 | remoteRef = E69E1C17203B3E9A00A2D664 /* PBXContainerItemProxy */; 792 | sourceTree = BUILT_PRODUCTS_DIR; 793 | }; 794 | E69E1C1A203B3E9A00A2D664 /* libfishhook-tvOS.a */ = { 795 | isa = PBXReferenceProxy; 796 | fileType = archive.ar; 797 | path = "libfishhook-tvOS.a"; 798 | remoteRef = E69E1C19203B3E9A00A2D664 /* PBXContainerItemProxy */; 799 | sourceTree = BUILT_PRODUCTS_DIR; 800 | }; 801 | E69E1C2D203B3E9A00A2D664 /* libjsinspector.a */ = { 802 | isa = PBXReferenceProxy; 803 | fileType = archive.ar; 804 | path = libjsinspector.a; 805 | remoteRef = E69E1C2C203B3E9A00A2D664 /* PBXContainerItemProxy */; 806 | sourceTree = BUILT_PRODUCTS_DIR; 807 | }; 808 | E69E1C2F203B3E9A00A2D664 /* libjsinspector-tvOS.a */ = { 809 | isa = PBXReferenceProxy; 810 | fileType = archive.ar; 811 | path = "libjsinspector-tvOS.a"; 812 | remoteRef = E69E1C2E203B3E9A00A2D664 /* PBXContainerItemProxy */; 813 | sourceTree = BUILT_PRODUCTS_DIR; 814 | }; 815 | E69E1C31203B3E9A00A2D664 /* libthird-party.a */ = { 816 | isa = PBXReferenceProxy; 817 | fileType = archive.ar; 818 | path = "libthird-party.a"; 819 | remoteRef = E69E1C30203B3E9A00A2D664 /* PBXContainerItemProxy */; 820 | sourceTree = BUILT_PRODUCTS_DIR; 821 | }; 822 | E69E1C33203B3E9A00A2D664 /* libthird-party.a */ = { 823 | isa = PBXReferenceProxy; 824 | fileType = archive.ar; 825 | path = "libthird-party.a"; 826 | remoteRef = E69E1C32203B3E9A00A2D664 /* PBXContainerItemProxy */; 827 | sourceTree = BUILT_PRODUCTS_DIR; 828 | }; 829 | E69E1C35203B3E9A00A2D664 /* libdouble-conversion.a */ = { 830 | isa = PBXReferenceProxy; 831 | fileType = archive.ar; 832 | path = "libdouble-conversion.a"; 833 | remoteRef = E69E1C34203B3E9A00A2D664 /* PBXContainerItemProxy */; 834 | sourceTree = BUILT_PRODUCTS_DIR; 835 | }; 836 | E69E1C37203B3E9A00A2D664 /* libdouble-conversion.a */ = { 837 | isa = PBXReferenceProxy; 838 | fileType = archive.ar; 839 | path = "libdouble-conversion.a"; 840 | remoteRef = E69E1C36203B3E9A00A2D664 /* PBXContainerItemProxy */; 841 | sourceTree = BUILT_PRODUCTS_DIR; 842 | }; 843 | E69E1C39203B3E9A00A2D664 /* libprivatedata.a */ = { 844 | isa = PBXReferenceProxy; 845 | fileType = archive.ar; 846 | path = libprivatedata.a; 847 | remoteRef = E69E1C38203B3E9A00A2D664 /* PBXContainerItemProxy */; 848 | sourceTree = BUILT_PRODUCTS_DIR; 849 | }; 850 | E69E1C3B203B3E9A00A2D664 /* libprivatedata-tvOS.a */ = { 851 | isa = PBXReferenceProxy; 852 | fileType = archive.ar; 853 | path = "libprivatedata-tvOS.a"; 854 | remoteRef = E69E1C3A203B3E9A00A2D664 /* PBXContainerItemProxy */; 855 | sourceTree = BUILT_PRODUCTS_DIR; 856 | }; 857 | /* End PBXReferenceProxy section */ 858 | 859 | /* Begin PBXResourcesBuildPhase section */ 860 | 13B07F8E1A680F5B00A75B9A /* Resources */ = { 861 | isa = PBXResourcesBuildPhase; 862 | buildActionMask = 2147483647; 863 | files = ( 864 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 865 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 866 | ); 867 | runOnlyForDeploymentPostprocessing = 0; 868 | }; 869 | /* End PBXResourcesBuildPhase section */ 870 | 871 | /* Begin PBXShellScriptBuildPhase section */ 872 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { 873 | isa = PBXShellScriptBuildPhase; 874 | buildActionMask = 2147483647; 875 | files = ( 876 | ); 877 | inputPaths = ( 878 | ); 879 | name = "Bundle React Native code and images"; 880 | outputPaths = ( 881 | ); 882 | runOnlyForDeploymentPostprocessing = 0; 883 | shellPath = /bin/sh; 884 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; 885 | }; 886 | /* End PBXShellScriptBuildPhase section */ 887 | 888 | /* Begin PBXSourcesBuildPhase section */ 889 | 13B07F871A680F5B00A75B9A /* Sources */ = { 890 | isa = PBXSourcesBuildPhase; 891 | buildActionMask = 2147483647; 892 | files = ( 893 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 894 | 13B07FC11A68108700A75B9A /* main.m in Sources */, 895 | ); 896 | runOnlyForDeploymentPostprocessing = 0; 897 | }; 898 | /* End PBXSourcesBuildPhase section */ 899 | 900 | /* Begin PBXVariantGroup section */ 901 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { 902 | isa = PBXVariantGroup; 903 | children = ( 904 | 13B07FB21A68108700A75B9A /* Base */, 905 | ); 906 | name = LaunchScreen.xib; 907 | path = example; 908 | sourceTree = ""; 909 | }; 910 | /* End PBXVariantGroup section */ 911 | 912 | /* Begin XCBuildConfiguration section */ 913 | 13B07F941A680F5B00A75B9A /* Debug */ = { 914 | isa = XCBuildConfiguration; 915 | buildSettings = { 916 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 917 | CURRENT_PROJECT_VERSION = 1; 918 | DEAD_CODE_STRIPPING = NO; 919 | DEVELOPMENT_TEAM = U7CY7GS6FN; 920 | INFOPLIST_FILE = example/Info.plist; 921 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 922 | OTHER_LDFLAGS = ( 923 | "$(inherited)", 924 | "-ObjC", 925 | "-lc++", 926 | ); 927 | PRODUCT_BUNDLE_IDENTIFIER = "com.github.cralpha.react-native-wkwebview.example"; 928 | PRODUCT_NAME = example; 929 | TARGETED_DEVICE_FAMILY = "1,2"; 930 | VERSIONING_SYSTEM = "apple-generic"; 931 | }; 932 | name = Debug; 933 | }; 934 | 13B07F951A680F5B00A75B9A /* Release */ = { 935 | isa = XCBuildConfiguration; 936 | buildSettings = { 937 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 938 | CURRENT_PROJECT_VERSION = 1; 939 | DEVELOPMENT_TEAM = U7CY7GS6FN; 940 | INFOPLIST_FILE = example/Info.plist; 941 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 942 | OTHER_LDFLAGS = ( 943 | "$(inherited)", 944 | "-ObjC", 945 | "-lc++", 946 | ); 947 | PRODUCT_BUNDLE_IDENTIFIER = "com.github.cralpha.react-native-wkwebview.example"; 948 | PRODUCT_NAME = example; 949 | TARGETED_DEVICE_FAMILY = "1,2"; 950 | VERSIONING_SYSTEM = "apple-generic"; 951 | }; 952 | name = Release; 953 | }; 954 | 83CBBA201A601CBA00E9B192 /* Debug */ = { 955 | isa = XCBuildConfiguration; 956 | buildSettings = { 957 | ALWAYS_SEARCH_USER_PATHS = NO; 958 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 959 | CLANG_CXX_LIBRARY = "libc++"; 960 | CLANG_ENABLE_MODULES = YES; 961 | CLANG_ENABLE_OBJC_ARC = YES; 962 | CLANG_WARN_BOOL_CONVERSION = YES; 963 | CLANG_WARN_CONSTANT_CONVERSION = YES; 964 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 965 | CLANG_WARN_EMPTY_BODY = YES; 966 | CLANG_WARN_ENUM_CONVERSION = YES; 967 | CLANG_WARN_INFINITE_RECURSION = YES; 968 | CLANG_WARN_INT_CONVERSION = YES; 969 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 970 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 971 | CLANG_WARN_UNREACHABLE_CODE = YES; 972 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 973 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 974 | COPY_PHASE_STRIP = NO; 975 | ENABLE_STRICT_OBJC_MSGSEND = YES; 976 | ENABLE_TESTABILITY = YES; 977 | GCC_C_LANGUAGE_STANDARD = gnu99; 978 | GCC_DYNAMIC_NO_PIC = NO; 979 | GCC_NO_COMMON_BLOCKS = YES; 980 | GCC_OPTIMIZATION_LEVEL = 0; 981 | GCC_PREPROCESSOR_DEFINITIONS = ( 982 | "DEBUG=1", 983 | "$(inherited)", 984 | ); 985 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 986 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 987 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 988 | GCC_WARN_UNDECLARED_SELECTOR = YES; 989 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 990 | GCC_WARN_UNUSED_FUNCTION = YES; 991 | GCC_WARN_UNUSED_VARIABLE = YES; 992 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 993 | MTL_ENABLE_DEBUG_INFO = YES; 994 | ONLY_ACTIVE_ARCH = YES; 995 | SDKROOT = iphoneos; 996 | }; 997 | name = Debug; 998 | }; 999 | 83CBBA211A601CBA00E9B192 /* Release */ = { 1000 | isa = XCBuildConfiguration; 1001 | buildSettings = { 1002 | ALWAYS_SEARCH_USER_PATHS = NO; 1003 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 1004 | CLANG_CXX_LIBRARY = "libc++"; 1005 | CLANG_ENABLE_MODULES = YES; 1006 | CLANG_ENABLE_OBJC_ARC = YES; 1007 | CLANG_WARN_BOOL_CONVERSION = YES; 1008 | CLANG_WARN_CONSTANT_CONVERSION = YES; 1009 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 1010 | CLANG_WARN_EMPTY_BODY = YES; 1011 | CLANG_WARN_ENUM_CONVERSION = YES; 1012 | CLANG_WARN_INFINITE_RECURSION = YES; 1013 | CLANG_WARN_INT_CONVERSION = YES; 1014 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 1015 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 1016 | CLANG_WARN_UNREACHABLE_CODE = YES; 1017 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 1018 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 1019 | COPY_PHASE_STRIP = YES; 1020 | ENABLE_NS_ASSERTIONS = NO; 1021 | ENABLE_STRICT_OBJC_MSGSEND = YES; 1022 | GCC_C_LANGUAGE_STANDARD = gnu99; 1023 | GCC_NO_COMMON_BLOCKS = YES; 1024 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 1025 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 1026 | GCC_WARN_UNDECLARED_SELECTOR = YES; 1027 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 1028 | GCC_WARN_UNUSED_FUNCTION = YES; 1029 | GCC_WARN_UNUSED_VARIABLE = YES; 1030 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1031 | MTL_ENABLE_DEBUG_INFO = NO; 1032 | SDKROOT = iphoneos; 1033 | VALIDATE_PRODUCT = YES; 1034 | }; 1035 | name = Release; 1036 | }; 1037 | /* End XCBuildConfiguration section */ 1038 | 1039 | /* Begin XCConfigurationList section */ 1040 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */ = { 1041 | isa = XCConfigurationList; 1042 | buildConfigurations = ( 1043 | 13B07F941A680F5B00A75B9A /* Debug */, 1044 | 13B07F951A680F5B00A75B9A /* Release */, 1045 | ); 1046 | defaultConfigurationIsVisible = 0; 1047 | defaultConfigurationName = Release; 1048 | }; 1049 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = { 1050 | isa = XCConfigurationList; 1051 | buildConfigurations = ( 1052 | 83CBBA201A601CBA00E9B192 /* Debug */, 1053 | 83CBBA211A601CBA00E9B192 /* Release */, 1054 | ); 1055 | defaultConfigurationIsVisible = 0; 1056 | defaultConfigurationName = Release; 1057 | }; 1058 | /* End XCConfigurationList section */ 1059 | }; 1060 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; 1061 | } 1062 | --------------------------------------------------------------------------------