Browse Source

merge master

Kesha Antonov 4 years ago
parent
commit
03870d4cb9
100 changed files with 5893 additions and 503 deletions
  1. 1
    1
      .circleci/config.yml
  2. 3
    3
      .github/workflows/detox.yml
  3. 108
    0
      .github/workflows/scripts/install-vs-features.ps1
  4. 67
    0
      .github/workflows/windows-ci.yml
  5. 6
    1
      .gitignore
  6. 15
    4
      README.md
  7. 31
    0
      __tests__/Alert.test.js
  8. 24
    15
      android/build.gradle
  9. 3
    3
      android/gradle.properties
  10. 201
    32
      android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
  11. 174
    75
      android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java
  12. 0
    27
      android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java
  13. 15
    0
      android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt
  14. 0
    0
      apple/RNCWKProcessPoolManager.h
  15. 0
    0
      apple/RNCWKProcessPoolManager.m
  16. 11
    0
      apple/RNCWebView.h
  17. 527
    168
      apple/RNCWebView.m
  18. 0
    0
      apple/RNCWebViewManager.h
  19. 12
    13
      apple/RNCWebViewManager.m
  20. 1
    0
      babel.config.js
  21. 1
    1
      bin/setup
  22. 46
    0
      docs/Contributing.md
  23. 14
    14
      docs/Custom-Android.md
  24. 45
    11
      docs/Getting-Started.md
  25. 202
    47
      docs/Guide.md
  26. 104
    0
      docs/README.portuguese.md
  27. 308
    88
      docs/Reference.md
  28. 1
    0
      example/.gitattributes
  29. 67
    0
      example/.gitignore
  30. 6
    0
      example/.prettierrc.js
  31. 1
    0
      example/.watchmanconfig
  32. 216
    0
      example/App.tsx
  33. 55
    0
      example/android/app/_BUCK
  34. 204
    0
      example/android/app/build.gradle
  35. 19
    0
      example/android/app/build_defs.bzl
  36. BIN
      example/android/app/debug.keystore
  37. 10
    0
      example/android/app/proguard-rules.pro
  38. 8
    0
      example/android/app/src/debug/AndroidManifest.xml
  39. 27
    0
      example/android/app/src/main/AndroidManifest.xml
  40. 15
    0
      example/android/app/src/main/java/com/example/MainActivity.java
  41. 76
    0
      example/android/app/src/main/java/com/example/MainApplication.java
  42. BIN
      example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  43. BIN
      example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  44. BIN
      example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  45. BIN
      example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  46. BIN
      example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  47. BIN
      example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  48. BIN
      example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  49. BIN
      example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  50. BIN
      example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  51. BIN
      example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  52. 3
    0
      example/android/app/src/main/res/values/strings.xml
  53. 9
    0
      example/android/app/src/main/res/values/styles.xml
  54. 38
    0
      example/android/build.gradle
  55. 21
    0
      example/android/gradle.properties
  56. BIN
      example/android/gradle/wrapper/gradle-wrapper.jar
  57. 5
    0
      example/android/gradle/wrapper/gradle-wrapper.properties
  58. 188
    0
      example/android/gradlew
  59. 100
    0
      example/android/gradlew.bat
  60. 5
    0
      example/android/settings.gradle
  61. 4
    0
      example/app.json
  62. 9
    0
      example/assets/test.html
  63. 3
    0
      example/babel.config.js
  64. 72
    0
      example/examples/Alerts.tsx
  65. 54
    0
      example/examples/Background.tsx
  66. 55
    0
      example/examples/Downloads.tsx
  67. 160
    0
      example/examples/Injection.tsx
  68. 16
    0
      example/examples/LocalPageLoad.tsx
  69. 68
    0
      example/examples/Scrolling.tsx
  70. 69
    0
      example/examples/Uploads.tsx
  71. 9
    0
      example/index.js
  72. 56
    0
      example/ios/Podfile
  73. 368
    0
      example/ios/Podfile.lock
  74. 53
    0
      example/ios/example-tvOS/Info.plist
  75. 24
    0
      example/ios/example-tvOSTests/Info.plist
  76. 929
    0
      example/ios/example.xcodeproj/project.pbxproj
  77. 88
    0
      example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme
  78. 88
    0
      example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme
  79. 10
    0
      example/ios/example.xcworkspace/contents.xcworkspacedata
  80. 8
    0
      example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  81. 15
    0
      example/ios/example/AppDelegate.h
  82. 42
    0
      example/ios/example/AppDelegate.m
  83. 42
    0
      example/ios/example/Base.lproj/LaunchScreen.xib
  84. 38
    0
      example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json
  85. 6
    0
      example/ios/example/Images.xcassets/Contents.json
  86. 57
    0
      example/ios/example/Info.plist
  87. 16
    0
      example/ios/example/main.m
  88. 24
    0
      example/ios/exampleTests/Info.plist
  89. 72
    0
      example/ios/exampleTests/exampleTests.m
  90. 42
    0
      example/macos/Podfile
  91. 199
    0
      example/macos/Podfile.lock
  92. 8
    0
      example/macos/example-iOS/AppDelegate.h
  93. 35
    0
      example/macos/example-iOS/AppDelegate.m
  94. 42
    0
      example/macos/example-iOS/Base.lproj/LaunchScreen.xib
  95. 38
    0
      example/macos/example-iOS/Images.xcassets/AppIcon.appiconset/Contents.json
  96. 6
    0
      example/macos/example-iOS/Images.xcassets/Contents.json
  97. 57
    0
      example/macos/example-iOS/Info.plist
  98. 9
    0
      example/macos/example-iOS/main.m
  99. 9
    0
      example/macos/example-macOS/AppDelegate.h
  100. 0
    0
      example/macos/example-macOS/AppDelegate.m

+ 1
- 1
.circleci/config.yml View File

34
             - node_modules-{{ arch }}-{{ checksum "yarn.lock" }}
34
             - node_modules-{{ arch }}-{{ checksum "yarn.lock" }}
35
 
35
 
36
       - run:
36
       - run:
37
-          name: Run Tests
37
+          name: Lint checks
38
           command: yarn ci
38
           command: yarn ci
39
 
39
 
40
   publish:
40
   publish:

+ 3
- 3
.github/workflows/detox.yml View File

1
 name: 'Detox CI Tests'
1
 name: 'Detox CI Tests'
2
-on: [push]
2
+on: [pull_request]
3
 
3
 
4
 jobs:
4
 jobs:
5
   tests:
5
   tests:
13
       - name: Setup - Install Yarn
13
       - name: Setup - Install Yarn
14
         run: YARN_GPG=NO curl -o- -L https://yarnpkg.com/install.sh | bash
14
         run: YARN_GPG=NO curl -o- -L https://yarnpkg.com/install.sh | bash
15
       - name: Setup - Install NPM Dependencies
15
       - name: Setup - Install NPM Dependencies
16
-        run: yarn
16
+        run: yarn --frozen-lockfile
17
       - name: Setup - Install CocoaPods CLI
17
       - name: Setup - Install CocoaPods CLI
18
-        run: sudo gem install cocoapods
18
+        run: sudo gem install cocoapods -v 1.8.4
19
       - name: Run tests
19
       - name: Run tests
20
         run: yarn ci
20
         run: yarn ci

+ 108
- 0
.github/workflows/scripts/install-vs-features.ps1 View File

1
+param (
2
+	[Parameter(Mandatory=$true)]
3
+	[string[]] $Components,
4
+
5
+	[uri] $InstallerUri = "https://download.visualstudio.microsoft.com/download/pr/c4fef23e-cc45-4836-9544-70e213134bc8/1ee5717e9a1e05015756dff77eb27d554a79a6db91f2716d836df368381af9a1/vs_Enterprise.exe",
6
+
7
+	[string] $VsInstaller = "${env:System_DefaultWorkingDirectory}\vs_Enterprise.exe",
8
+
9
+	[string] $VsInstallOutputDir = "${env:System_DefaultWorkingDirectory}\vs",
10
+
11
+	[System.IO.FileInfo] $VsInstallPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise",
12
+
13
+	[System.IO.FileInfo] $VsInstallerPath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer",
14
+
15
+	[switch] $Collect = $false,
16
+
17
+	[switch] $Cleanup = $false,
18
+
19
+	[switch] $UseWebInstaller = $false
20
+)
21
+
22
+$Components | ForEach-Object {
23
+	$componentList += '--add', $_
24
+}
25
+
26
+$LocalVsInstaller = "$VsInstallerPath\vs_installershell.exe"
27
+
28
+$UseWebInstaller = $UseWebInstaller -or -not (Test-Path -Path "$LocalVsInstaller")
29
+
30
+if ($UseWebInstaller) {
31
+	Write-Host "Downloading web installer..."
32
+
33
+	Invoke-WebRequest -Method Get `
34
+		-Uri $InstallerUri `
35
+		-OutFile $VsInstaller
36
+
37
+	New-Item -ItemType directory -Path $VsInstallOutputDir
38
+
39
+	Write-Host "Running web installer to download requested components..."
40
+
41
+	Start-Process `
42
+		-FilePath "$VsInstaller" `
43
+		-ArgumentList ( `
44
+			'--layout', "$VsInstallOutputDir",
45
+			'--wait',
46
+			'--norestart',
47
+			'--quiet' + `
48
+			$componentList
49
+		) `
50
+		-Wait `
51
+		-PassThru
52
+
53
+	Write-Host "Running downloaded VS installer to add requested components..."
54
+
55
+	Start-Process `
56
+		-FilePath "$VsInstallOutputDir\vs_Enterprise.exe" `
57
+		-ArgumentList (
58
+			'modify',
59
+			'--installPath', "`"$VsInstallPath`"" ,
60
+			'--wait',
61
+			'--norestart',
62
+			'--quiet' + `
63
+			$componentList
64
+		) `
65
+		-Wait `
66
+		-PassThru `
67
+		-OutVariable returnCode
68
+
69
+	if ($Cleanup) {
70
+		Write-Host "Cleaning up..."
71
+
72
+		Remove-Item -Path $VsInstaller
73
+		Remove-Item -Path $VsInstallOutputDir -Recurse
74
+	}
75
+	
76
+} else {
77
+	Write-Host "Running local installer to add requested components..."
78
+
79
+	Start-Process `
80
+		-FilePath "$LocalVsInstaller" `
81
+		-ArgumentList (
82
+			'modify',
83
+			'--installPath', "`"$VsInstallPath`"" ,
84
+			'--norestart',
85
+			'--quiet' + `
86
+			$componentList
87
+		) `
88
+		-Wait `
89
+		-OutVariable returnCode
90
+}
91
+
92
+if ($Collect) {
93
+	Invoke-WebRequest -Method Get `
94
+		-Uri 'https://download.microsoft.com/download/8/3/4/834E83F6-C377-4DCE-A757-69A418B6C6DF/Collect.exe' `
95
+		-OutFile ${env:System_DefaultWorkingDirectory}\Collect.exe
96
+
97
+	# Should generate ${env:Temp}\vslogs.zip
98
+	Start-Process `
99
+		-FilePath "${env:System_DefaultWorkingDirectory}\Collect.exe" `
100
+		-Wait `
101
+		-PassThru
102
+
103
+	New-Item -ItemType Directory -Force ${env:System_DefaultWorkingDirectory}\vslogs
104
+	Expand-Archive -Path ${env:TEMP}\vslogs.zip -DestinationPath ${env:System_DefaultWorkingDirectory}\vslogs\
105
+
106
+	Write-Host "VC versions after installation:"
107
+	Get-ChildItem -Name "$VsInstallPath\VC\Tools\MSVC\"
108
+}

+ 67
- 0
.github/workflows/windows-ci.yml View File

1
+name: Windows CI
2
+on: [pull_request]
3
+
4
+jobs:
5
+  run-windows-tests:
6
+    name: Build & run tests
7
+    runs-on: windows-2019
8
+
9
+    steps:
10
+    - uses: actions/checkout@v2
11
+      name: Checkout Code
12
+     
13
+    - name: Setup Node.js
14
+      uses: actions/setup-node@v1
15
+      with:
16
+        node-version: '12.9.1'
17
+
18
+    - name: Install Visual Studio components
19
+      shell: powershell
20
+      run: .\.github\workflows\scripts\install-vs-features.ps1 Microsoft.VisualStudio.Component.VC.v141.x86.x64,Microsoft.VisualStudio.ComponentGroup.UWP.VC.v141
21
+
22
+    - name: Setup MSBuild
23
+      uses: microsoft/setup-msbuild@v1.0.0
24
+      with:
25
+        vs-version: 16.5
26
+       
27
+    - name: Setup NuGet
28
+      uses: NuGet/setup-nuget@v1.0.2
29
+
30
+    - name: Check node modules cache
31
+      uses: actions/cache@v1
32
+      id: yarn-cache
33
+      with:
34
+        path: ./node_modules
35
+        key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
36
+        restore-keys: |
37
+          ${{ runner.os }}-yarn-
38
+
39
+    - name: Install node modules
40
+      if: steps.yarn-cache.outputs.cache-hit != 'true'
41
+      run: yarn --pure-lockfile
42
+    
43
+    - name: yarn build
44
+      if: steps.yarn-cache.outputs.cache-hit == 'true'
45
+      run: |
46
+        yarn build
47
+        yarn tsc
48
+ 
49
+    - name: NuGet restore
50
+      run: nuget restore example\windows\WebViewWindows.sln
51
+
52
+    - name: Build x64 release
53
+      run: msbuild example\windows\WebViewWindows.sln /p:Configuration=Release /p:Platform=x64 -m
54
+
55
+    - name: Deploy
56
+      shell: powershell
57
+      run: |
58
+        cd example
59
+        Copy-Item -Path windows\x64\Release -Recurse -Destination windows\
60
+        npx react-native run-windows --arch x64 --release --no-build --no-packager
61
+
62
+    - name: Start Appium server
63
+      shell: powershell
64
+      run: Start-Process PowerShell -ArgumentList "yarn appium"
65
+      
66
+    - name: Run tests
67
+      run: yarn test:windows

+ 6
- 1
.gitignore View File

53
 android/gradlew
53
 android/gradlew
54
 android/gradlew.bat
54
 android/gradlew.bat
55
 
55
 
56
-lib/
56
+lib/
57
+.classpath
58
+.project
59
+.settings/
60
+msbuild.binlog
61
+example/msbuild.binlog

+ 15
- 4
README.md View File

4
 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
4
 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
5
 [![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors)
5
 [![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors)
6
 [![Known Vulnerabilities](https://snyk.io/test/github/react-native-community/react-native-webview/badge.svg?style=flat-square)](https://snyk.io/test/github/react-native-community/react-native-webview)
6
 [![Known Vulnerabilities](https://snyk.io/test/github/react-native-community/react-native-webview/badge.svg?style=flat-square)](https://snyk.io/test/github/react-native-community/react-native-webview)
7
-<a href="https://www.npmjs.com/package/react-native-webview"><img src="https://img.shields.io/npm/v/react-native-webview.svg"></a>
7
+[![NPM Version](https://img.shields.io/npm/v/react-native-webview.svg?style=flat-square)](https://www.npmjs.com/package/react-native-webview)
8
+[![Lean Core Extracted](https://img.shields.io/badge/Lean%20Core-Extracted-brightgreen.svg?style=flat-square)][lean-core-issue]
8
 
9
 
9
 **React Native WebView** is a modern, well-supported, and cross-platform WebView for React Native. It is intended to be a replacement for the built-in WebView (which will be [removed from core](https://github.com/react-native-community/discussions-and-proposals/pull/3)).
10
 **React Native WebView** is a modern, well-supported, and cross-platform WebView for React Native. It is intended to be a replacement for the built-in WebView (which will be [removed from core](https://github.com/react-native-community/discussions-and-proposals/pull/3)).
10
 
11
 
19
 
20
 
20
 - [x] iOS
21
 - [x] iOS
21
 - [x] Android
22
 - [x] Android
23
+- [x] macOS
24
+- [x] Windows
22
 
25
 
23
 _Note: Expo support for React Native WebView started with [Expo SDK v33.0.0](https://blog.expo.io/expo-sdk-v33-0-0-is-now-available-52d1c99dfe4c)._
26
 _Note: Expo support for React Native WebView started with [Expo SDK v33.0.0](https://blog.expo.io/expo-sdk-v33-0-0-is-now-available-52d1c99dfe4c)._
24
 
27
 
34
 
37
 
35
 Current Version: ![version](https://img.shields.io/npm/v/react-native-webview.svg)
38
 Current Version: ![version](https://img.shields.io/npm/v/react-native-webview.svg)
36
 
39
 
40
+- [8.0.0](https://github.com/react-native-community/react-native-webview/releases/tag/v8.0.0) - onNavigationStateChange now triggers with hash url changes
41
+
37
 - [7.0.1](https://github.com/react-native-community/react-native-webview/releases/tag/v7.0.1) - Removed UIWebView
42
 - [7.0.1](https://github.com/react-native-community/react-native-webview/releases/tag/v7.0.1) - Removed UIWebView
38
 
43
 
39
 - [6.0.**2**](https://github.com/react-native-community/react-native-webview/releases/tag/v6.0.2) - Update to AndroidX. Make sure to enable it in your project's `android/gradle.properties`. See [Getting Started Guide](docs/Getting-Started.md).
44
 - [6.0.**2**](https://github.com/react-native-community/react-native-webview/releases/tag/v6.0.2) - Update to AndroidX. Make sure to enable it in your project's `android/gradle.properties`. See [Getting Started Guide](docs/Getting-Started.md).
61
 // ...
66
 // ...
62
 class MyWebComponent extends Component {
67
 class MyWebComponent extends Component {
63
   render() {
68
   render() {
64
-    return (
65
-      <WebView source={{ uri: 'https://facebook.github.io/react-native/' }} />
66
-    );
69
+    return <WebView source={{ uri: 'https://reactnative.dev/' }} />;
67
   }
70
   }
68
 }
71
 }
69
 ```
72
 ```
93
 ## License
96
 ## License
94
 
97
 
95
 MIT
98
 MIT
99
+
100
+## Translations
101
+
102
+This readme is available in:
103
+
104
+- [Brazilian portuguese](docs/README.portuguese.md)
105
+
106
+[lean-core-issue]: https://github.com/facebook/react-native/issues/23313

+ 31
- 0
__tests__/Alert.test.js View File

1
+/**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+import { driver, By2 } from 'selenium-appium'
7
+import { until } from 'selenium-webdriver';
8
+
9
+const setup = require('../jest-setups/jest.setup');
10
+jest.setTimeout(50000);
11
+
12
+beforeAll(() => {
13
+  return driver.startWithCapabilities(setup.capabilites);
14
+});
15
+
16
+afterAll(() => {
17
+  return driver.quit();
18
+});
19
+
20
+describe('Alert Tests', () => {
21
+  
22
+  test('Show Alert', async () => {
23
+    const showAlertButton = await driver.wait(until.elementLocated(By2.nativeName('Show alert')));
24
+    await showAlertButton.click();
25
+    await driver.wait(until.elementLocated(By2.nativeName('Hello! I am an alert box!')));
26
+    await By2.nativeName('OK').click();
27
+    const dismissMessage = await driver.wait(until.elementLocated(By2.nativeName('Alert dismissed!')));
28
+    expect(dismissMessage).not.toBeNull();
29
+  });
30
+
31
+});

+ 24
- 15
android/build.gradle View File

1
 buildscript {
1
 buildscript {
2
-  //Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
-  def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['ReactNativeWebView_kotlinVersion']
4
-
5
-  repositories {
6
-    google()
7
-    jcenter()
2
+  ext.getExtOrDefault = {name ->
3
+    return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeWebView_' + name]
8
   }
4
   }
9
 
5
 
10
-  dependencies {
11
-    classpath 'com.android.tools.build:gradle:3.2.1'
12
-    //noinspection DifferentKotlinGradleVersion
13
-    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14
-  }
15
-}
6
+  // The Android Gradle plugin is only required when opening the android folder stand-alone.
7
+  // This avoids unnecessary downloads and potential conflicts when the library is included as a
8
+  // module dependency in an application project.
9
+  if (project == rootProject) {
10
+    repositories {
11
+      google()
12
+      jcenter()
13
+    }
14
+
15
+    dependencies {
16
+      classpath("com.android.tools.build:gradle:3.6.0")
17
+      classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}")
18
+    }
19
+  } else {
20
+    repositories {
21
+      jcenter()
22
+    }
16
 
23
 
17
-def getExtOrDefault(name) {
18
-  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeWebView_' + name]
24
+    dependencies {
25
+      classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}")
26
+    }
27
+  }
19
 }
28
 }
20
 
29
 
21
 def getExtOrIntegerDefault(name) {
30
 def getExtOrIntegerDefault(name) {
123
 
132
 
124
 dependencies {
133
 dependencies {
125
   //noinspection GradleDynamicVersion
134
   //noinspection GradleDynamicVersion
126
-  api 'com.facebook.react:react-native:+'
135
+  implementation 'com.facebook.react:react-native:+'
127
   implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
136
   implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
128
 }
137
 }

+ 3
- 3
android/gradle.properties View File

1
-ReactNativeWebView_kotlinVersion=1.3.11
2
-ReactNativeWebView_compileSdkVersion=28
3
-ReactNativeWebView_buildToolsVersion=28.0.3
1
+ReactNativeWebView_kotlinVersion=1.3.50
2
+ReactNativeWebView_compileSdkVersion=29
3
+ReactNativeWebView_buildToolsVersion=29.0.3
4
 ReactNativeWebView_targetSdkVersion=28
4
 ReactNativeWebView_targetSdkVersion=28

+ 201
- 32
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java View File

41
 import com.facebook.react.views.scroll.ScrollEventType;
41
 import com.facebook.react.views.scroll.ScrollEventType;
42
 import com.facebook.react.views.scroll.OnScrollDispatchHelper;
42
 import com.facebook.react.views.scroll.OnScrollDispatchHelper;
43
 import com.facebook.react.bridge.Arguments;
43
 import com.facebook.react.bridge.Arguments;
44
+import com.facebook.react.bridge.CatalystInstance;
44
 import com.facebook.react.bridge.LifecycleEventListener;
45
 import com.facebook.react.bridge.LifecycleEventListener;
45
 import com.facebook.react.bridge.ReactContext;
46
 import com.facebook.react.bridge.ReactContext;
46
 import com.facebook.react.bridge.ReadableArray;
47
 import com.facebook.react.bridge.ReadableArray;
47
 import com.facebook.react.bridge.ReadableMap;
48
 import com.facebook.react.bridge.ReadableMap;
48
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
49
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
49
 import com.facebook.react.bridge.WritableMap;
50
 import com.facebook.react.bridge.WritableMap;
51
+import com.facebook.react.bridge.WritableNativeArray;
52
+import com.facebook.react.bridge.WritableNativeMap;
50
 import com.facebook.react.common.MapBuilder;
53
 import com.facebook.react.common.MapBuilder;
51
 import com.facebook.react.common.build.ReactBuildConfig;
54
 import com.facebook.react.common.build.ReactBuildConfig;
52
 import com.facebook.react.module.annotations.ReactModule;
55
 import com.facebook.react.module.annotations.ReactModule;
106
 @ReactModule(name = RNCWebViewManager.REACT_CLASS)
109
 @ReactModule(name = RNCWebViewManager.REACT_CLASS)
107
 public class RNCWebViewManager extends SimpleViewManager<WebView> {
110
 public class RNCWebViewManager extends SimpleViewManager<WebView> {
108
 
111
 
109
-  public static String activeUrl = null;
110
   public static final int COMMAND_GO_BACK = 1;
112
   public static final int COMMAND_GO_BACK = 1;
111
   public static final int COMMAND_GO_FORWARD = 2;
113
   public static final int COMMAND_GO_FORWARD = 2;
112
   public static final int COMMAND_RELOAD = 3;
114
   public static final int COMMAND_RELOAD = 3;
115
   public static final int COMMAND_INJECT_JAVASCRIPT = 6;
117
   public static final int COMMAND_INJECT_JAVASCRIPT = 6;
116
   public static final int COMMAND_LOAD_URL = 7;
118
   public static final int COMMAND_LOAD_URL = 7;
117
   public static final int COMMAND_FOCUS = 8;
119
   public static final int COMMAND_FOCUS = 8;
120
+
121
+  // android commands
122
+  public static final int COMMAND_CLEAR_FORM_DATA = 1000;
123
+  public static final int COMMAND_CLEAR_CACHE = 1001;
124
+  public static final int COMMAND_CLEAR_HISTORY = 1002;
125
+
118
   protected static final String REACT_CLASS = "RNCWebView";
126
   protected static final String REACT_CLASS = "RNCWebView";
119
   protected static final String HTML_ENCODING = "UTF-8";
127
   protected static final String HTML_ENCODING = "UTF-8";
120
   protected static final String HTML_MIME_TYPE = "text/html";
128
   protected static final String HTML_MIME_TYPE = "text/html";
188
 
196
 
189
     webView.setDownloadListener(new DownloadListener() {
197
     webView.setDownloadListener(new DownloadListener() {
190
       public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
198
       public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
199
+        webView.setIgnoreErrFailedForThisURL(url);
200
+
191
         RNCWebViewModule module = getModule(reactContext);
201
         RNCWebViewModule module = getModule(reactContext);
192
 
202
 
193
         DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
203
         DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
202
           String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost();
212
           String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost();
203
           String cookie = CookieManager.getInstance().getCookie(baseUrl);
213
           String cookie = CookieManager.getInstance().getCookie(baseUrl);
204
           request.addRequestHeader("Cookie", cookie);
214
           request.addRequestHeader("Cookie", cookie);
205
-          System.out.println("Got cookie for DownloadManager: " + cookie);
206
         } catch (MalformedURLException e) {
215
         } catch (MalformedURLException e) {
207
           System.out.println("Error getting cookie for DownloadManager: " + e.toString());
216
           System.out.println("Error getting cookie for DownloadManager: " + e.toString());
208
           e.printStackTrace();
217
           e.printStackTrace();
257
     }
266
     }
258
   }
267
   }
259
 
268
 
269
+  @ReactProp(name = "cacheMode")
270
+  public void setCacheMode(WebView view, String cacheModeString) {
271
+    Integer cacheMode;
272
+    switch (cacheModeString) {
273
+      case "LOAD_CACHE_ONLY":
274
+        cacheMode = WebSettings.LOAD_CACHE_ONLY;
275
+        break;
276
+      case "LOAD_CACHE_ELSE_NETWORK":
277
+        cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK;
278
+        break;
279
+      case "LOAD_NO_CACHE":
280
+        cacheMode = WebSettings.LOAD_NO_CACHE;
281
+        break;
282
+      case "LOAD_DEFAULT":
283
+      default:
284
+        cacheMode = WebSettings.LOAD_DEFAULT;
285
+        break;
286
+    }
287
+    view.getSettings().setCacheMode(cacheMode);
288
+  }
289
+
260
   @ReactProp(name = "androidHardwareAccelerationDisabled")
290
   @ReactProp(name = "androidHardwareAccelerationDisabled")
261
   public void setHardwareAccelerationDisabled(WebView view, boolean disabled) {
291
   public void setHardwareAccelerationDisabled(WebView view, boolean disabled) {
262
-    ReactContext reactContext = (ReactContext) view.getContext();
263
-    final boolean isHardwareAccelerated = (reactContext.getCurrentActivity().getWindow()
264
-        .getAttributes().flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
265
-    if (disabled || !isHardwareAccelerated) {
292
+    if (disabled) {
266
       view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
293
       view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
267
-    } else {
268
-      view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
269
     }
294
     }
270
   }
295
   }
271
 
296
 
350
     view.getSettings().setMediaPlaybackRequiresUserGesture(requires);
375
     view.getSettings().setMediaPlaybackRequiresUserGesture(requires);
351
   }
376
   }
352
 
377
 
378
+  @ReactProp(name = "javaScriptCanOpenWindowsAutomatically")
379
+  public void setJavaScriptCanOpenWindowsAutomatically(WebView view, boolean enabled) {
380
+    view.getSettings().setJavaScriptCanOpenWindowsAutomatically(enabled);
381
+  }
382
+
383
+  @ReactProp(name = "allowFileAccessFromFileURLs")
384
+  public void setAllowFileAccessFromFileURLs(WebView view, boolean allow) {
385
+    view.getSettings().setAllowFileAccessFromFileURLs(allow);
386
+  }
387
+
353
   @ReactProp(name = "allowUniversalAccessFromFileURLs")
388
   @ReactProp(name = "allowUniversalAccessFromFileURLs")
354
   public void setAllowUniversalAccessFromFileURLs(WebView view, boolean allow) {
389
   public void setAllowUniversalAccessFromFileURLs(WebView view, boolean allow) {
355
     view.getSettings().setAllowUniversalAccessFromFileURLs(allow);
390
     view.getSettings().setAllowUniversalAccessFromFileURLs(allow);
369
   public void setMessagingEnabled(WebView view, boolean enabled) {
404
   public void setMessagingEnabled(WebView view, boolean enabled) {
370
     ((RNCWebView) view).setMessagingEnabled(enabled);
405
     ((RNCWebView) view).setMessagingEnabled(enabled);
371
   }
406
   }
372
-   
407
+
408
+  @ReactProp(name = "messagingModuleName")
409
+  public void setMessagingModuleName(WebView view, String moduleName) {
410
+    ((RNCWebView) view).setMessagingModuleName(moduleName);
411
+  }
412
+
373
   @ReactProp(name = "incognito")
413
   @ReactProp(name = "incognito")
374
   public void setIncognito(WebView view, boolean enabled) {
414
   public void setIncognito(WebView view, boolean enabled) {
375
     // Remove all previous cookies
415
     // Remove all previous cookies
524
   @Override
564
   @Override
525
   public @Nullable
565
   public @Nullable
526
   Map<String, Integer> getCommandsMap() {
566
   Map<String, Integer> getCommandsMap() {
527
-    Map map = MapBuilder.of(
528
-      "goBack", COMMAND_GO_BACK,
529
-      "goForward", COMMAND_GO_FORWARD,
530
-      "reload", COMMAND_RELOAD,
531
-      "stopLoading", COMMAND_STOP_LOADING,
532
-      "postMessage", COMMAND_POST_MESSAGE,
533
-      "injectJavaScript", COMMAND_INJECT_JAVASCRIPT,
534
-      "loadUrl", COMMAND_LOAD_URL
535
-    );
536
-    map.put("requestFocus", COMMAND_FOCUS);
537
-    return map;
567
+    return MapBuilder.<String, Integer>builder()
568
+      .put("goBack", COMMAND_GO_BACK)
569
+      .put("goForward", COMMAND_GO_FORWARD)
570
+      .put("reload", COMMAND_RELOAD)
571
+      .put("stopLoading", COMMAND_STOP_LOADING)
572
+      .put("postMessage", COMMAND_POST_MESSAGE)
573
+      .put("injectJavaScript", COMMAND_INJECT_JAVASCRIPT)
574
+      .put("loadUrl", COMMAND_LOAD_URL)
575
+      .put("requestFocus", COMMAND_FOCUS)
576
+      .put("clearFormData", COMMAND_CLEAR_FORM_DATA)
577
+      .put("clearCache", COMMAND_CLEAR_CACHE)
578
+      .put("clearHistory", COMMAND_CLEAR_HISTORY)
579
+      .build();
538
   }
580
   }
539
 
581
 
540
   @Override
582
   @Override
580
         if (args == null) {
622
         if (args == null) {
581
           throw new RuntimeException("Arguments for loading an url are null!");
623
           throw new RuntimeException("Arguments for loading an url are null!");
582
         }
624
         }
625
+        ((RNCWebView) root).progressChangedFilter.setWaitingForCommandLoadUrl(false);
583
         root.loadUrl(args.getString(0));
626
         root.loadUrl(args.getString(0));
584
         break;
627
         break;
585
       case COMMAND_FOCUS:
628
       case COMMAND_FOCUS:
586
         root.requestFocus();
629
         root.requestFocus();
587
         break;
630
         break;
631
+      case COMMAND_CLEAR_FORM_DATA:
632
+        root.clearFormData();
633
+        break;
634
+      case COMMAND_CLEAR_CACHE:
635
+        boolean includeDiskFiles = args != null && args.getBoolean(0);
636
+        root.clearCache(includeDiskFiles);
637
+        break;
638
+      case COMMAND_CLEAR_HISTORY:
639
+        root.clearHistory();
640
+        break;
588
     }
641
     }
589
   }
642
   }
590
 
643
 
603
     if (mAllowsFullscreenVideo) {
656
     if (mAllowsFullscreenVideo) {
604
       int initialRequestedOrientation = reactContext.getCurrentActivity().getRequestedOrientation();
657
       int initialRequestedOrientation = reactContext.getCurrentActivity().getRequestedOrientation();
605
       mWebChromeClient = new RNCWebChromeClient(reactContext, webView) {
658
       mWebChromeClient = new RNCWebChromeClient(reactContext, webView) {
659
+        @Override
660
+        public Bitmap getDefaultVideoPoster() {
661
+          return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888);
662
+        }
663
+
606
         @Override
664
         @Override
607
         public void onShowCustomView(View view, CustomViewCallback callback) {
665
         public void onShowCustomView(View view, CustomViewCallback callback) {
608
           if (mVideoView != null) {
666
           if (mVideoView != null) {
655
       if (mWebChromeClient != null) {
713
       if (mWebChromeClient != null) {
656
         mWebChromeClient.onHideCustomView();
714
         mWebChromeClient.onHideCustomView();
657
       }
715
       }
658
-      mWebChromeClient = new RNCWebChromeClient(reactContext, webView);
716
+      mWebChromeClient = new RNCWebChromeClient(reactContext, webView) {
717
+        @Override
718
+        public Bitmap getDefaultVideoPoster() {
719
+          return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888);
720
+        }
721
+      };
659
       webView.setWebChromeClient(mWebChromeClient);
722
       webView.setWebChromeClient(mWebChromeClient);
660
     }
723
     }
661
   }
724
   }
665
     protected boolean mLastLoadFailed = false;
728
     protected boolean mLastLoadFailed = false;
666
     protected @Nullable
729
     protected @Nullable
667
     ReadableArray mUrlPrefixesForDefaultIntent;
730
     ReadableArray mUrlPrefixesForDefaultIntent;
731
+    protected RNCWebView.ProgressChangedFilter progressChangedFilter = null;
732
+    protected @Nullable String ignoreErrFailedForThisURL = null;
733
+
734
+    public void setIgnoreErrFailedForThisURL(@Nullable String url) {
735
+      ignoreErrFailedForThisURL = url;
736
+    }
668
 
737
 
669
     @Override
738
     @Override
670
     public void onPageFinished(WebView webView, String url) {
739
     public void onPageFinished(WebView webView, String url) {
693
 
762
 
694
     @Override
763
     @Override
695
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
764
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
696
-      activeUrl = url;
765
+      progressChangedFilter.setWaitingForCommandLoadUrl(true);
697
       dispatchEvent(
766
       dispatchEvent(
698
         view,
767
         view,
699
         new TopShouldStartLoadWithRequestEvent(
768
         new TopShouldStartLoadWithRequestEvent(
716
       int errorCode,
785
       int errorCode,
717
       String description,
786
       String description,
718
       String failingUrl) {
787
       String failingUrl) {
788
+
789
+      if (ignoreErrFailedForThisURL != null
790
+          && failingUrl.equals(ignoreErrFailedForThisURL)
791
+          && errorCode == -1
792
+          && description.equals("net::ERR_FAILED")) {
793
+
794
+        // This is a workaround for a bug in the WebView.
795
+        // See these chromium issues for more context:
796
+        // https://bugs.chromium.org/p/chromium/issues/detail?id=1023678
797
+        // https://bugs.chromium.org/p/chromium/issues/detail?id=1050635
798
+        // This entire commit should be reverted once this bug is resolved in chromium.
799
+        setIgnoreErrFailedForThisURL(null);
800
+        return;
801
+      }
802
+
719
       super.onReceivedError(webView, errorCode, description, failingUrl);
803
       super.onReceivedError(webView, errorCode, description, failingUrl);
720
       mLastLoadFailed = true;
804
       mLastLoadFailed = true;
721
 
805
 
775
     public void setUrlPrefixesForDefaultIntent(ReadableArray specialUrls) {
859
     public void setUrlPrefixesForDefaultIntent(ReadableArray specialUrls) {
776
       mUrlPrefixesForDefaultIntent = specialUrls;
860
       mUrlPrefixesForDefaultIntent = specialUrls;
777
     }
861
     }
862
+
863
+    public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) {
864
+      progressChangedFilter = filter;
865
+    }
778
   }
866
   }
779
 
867
 
780
   protected static class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener {
868
   protected static class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener {
796
     protected View mVideoView;
884
     protected View mVideoView;
797
     protected WebChromeClient.CustomViewCallback mCustomViewCallback;
885
     protected WebChromeClient.CustomViewCallback mCustomViewCallback;
798
 
886
 
887
+    protected RNCWebView.ProgressChangedFilter progressChangedFilter = null;
888
+
799
     public RNCWebChromeClient(ReactContext reactContext, WebView webView) {
889
     public RNCWebChromeClient(ReactContext reactContext, WebView webView) {
800
       this.mReactContext = reactContext;
890
       this.mReactContext = reactContext;
801
       this.mWebView = webView;
891
       this.mWebView = webView;
811
     }
901
     }
812
 
902
 
813
     // Fix WebRTC permission request error.
903
     // Fix WebRTC permission request error.
904
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
814
     @Override
905
     @Override
815
     public void onPermissionRequest(final PermissionRequest request) {
906
     public void onPermissionRequest(final PermissionRequest request) {
816
       String[] requestedResources = request.getResources();
907
       String[] requestedResources = request.getResources();
849
     public void onProgressChanged(WebView webView, int newProgress) {
940
     public void onProgressChanged(WebView webView, int newProgress) {
850
       super.onProgressChanged(webView, newProgress);
941
       super.onProgressChanged(webView, newProgress);
851
       final String url = webView.getUrl();
942
       final String url = webView.getUrl();
852
-      if (
853
-        url != null
854
-        && activeUrl != null
855
-        && !url.equals(activeUrl)
856
-      ) {
943
+      if (progressChangedFilter.isWaitingForCommandLoadUrl()) {
857
         return;
944
         return;
858
       }
945
       }
859
       WritableMap event = Arguments.createMap();
946
       WritableMap event = Arguments.createMap();
892
     public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
979
     public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
893
       String[] acceptTypes = fileChooserParams.getAcceptTypes();
980
       String[] acceptTypes = fileChooserParams.getAcceptTypes();
894
       boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
981
       boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
895
-      Intent intent = fileChooserParams.createIntent();
896
-      return getModule(mReactContext).startPhotoPickerIntent(filePathCallback, intent, acceptTypes, allowMultiple);
982
+      return getModule(mReactContext).startPhotoPickerIntent(filePathCallback, acceptTypes, allowMultiple);
897
     }
983
     }
898
 
984
 
899
     @Override
985
     @Override
912
     protected ViewGroup getRootView() {
998
     protected ViewGroup getRootView() {
913
       return (ViewGroup) mReactContext.getCurrentActivity().findViewById(android.R.id.content);
999
       return (ViewGroup) mReactContext.getCurrentActivity().findViewById(android.R.id.content);
914
     }
1000
     }
1001
+
1002
+    public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) {
1003
+      progressChangedFilter = filter;
1004
+    }
915
   }
1005
   }
916
 
1006
 
917
   /**
1007
   /**
923
     String injectedJS;
1013
     String injectedJS;
924
     protected boolean messagingEnabled = false;
1014
     protected boolean messagingEnabled = false;
925
     protected @Nullable
1015
     protected @Nullable
1016
+    String messagingModuleName;
1017
+    protected @Nullable
926
     RNCWebViewClient mRNCWebViewClient;
1018
     RNCWebViewClient mRNCWebViewClient;
1019
+    protected @Nullable
1020
+    CatalystInstance mCatalystInstance;
927
     protected boolean sendContentSizeChangeEvents = false;
1021
     protected boolean sendContentSizeChangeEvents = false;
928
     private OnScrollDispatchHelper mOnScrollDispatchHelper;
1022
     private OnScrollDispatchHelper mOnScrollDispatchHelper;
929
     protected boolean hasScrollEvent = false;
1023
     protected boolean hasScrollEvent = false;
1024
+    protected ProgressChangedFilter progressChangedFilter;
930
 
1025
 
931
     /**
1026
     /**
932
      * WebView must be created with an context of the current activity
1027
      * WebView must be created with an context of the current activity
936
      */
1031
      */
937
     public RNCWebView(ThemedReactContext reactContext) {
1032
     public RNCWebView(ThemedReactContext reactContext) {
938
       super(reactContext);
1033
       super(reactContext);
1034
+      progressChangedFilter = new ProgressChangedFilter();
1035
+    }
1036
+
1037
+    public void setIgnoreErrFailedForThisURL(String url) {
1038
+      mRNCWebViewClient.setIgnoreErrFailedForThisURL(url);
939
     }
1039
     }
940
 
1040
 
941
     public void setSendContentSizeChangeEvents(boolean sendContentSizeChangeEvents) {
1041
     public void setSendContentSizeChangeEvents(boolean sendContentSizeChangeEvents) {
980
     @Override
1080
     @Override
981
     public void setWebViewClient(WebViewClient client) {
1081
     public void setWebViewClient(WebViewClient client) {
982
       super.setWebViewClient(client);
1082
       super.setWebViewClient(client);
983
-      mRNCWebViewClient = (RNCWebViewClient) client;
1083
+      if (client instanceof RNCWebViewClient) {
1084
+        mRNCWebViewClient = (RNCWebViewClient) client;
1085
+        mRNCWebViewClient.setProgressChangedFilter(progressChangedFilter);
1086
+      }
1087
+    }
1088
+
1089
+    WebChromeClient mWebChromeClient;
1090
+    @Override
1091
+    public void setWebChromeClient(WebChromeClient client) {
1092
+      this.mWebChromeClient = client;
1093
+      super.setWebChromeClient(client);
1094
+      if (client instanceof RNCWebChromeClient) {
1095
+        ((RNCWebChromeClient) client).setProgressChangedFilter(progressChangedFilter);
1096
+      }
984
     }
1097
     }
985
 
1098
 
986
     public @Nullable
1099
     public @Nullable
996
       return new RNCWebViewBridge(webView);
1109
       return new RNCWebViewBridge(webView);
997
     }
1110
     }
998
 
1111
 
1112
+    protected void createCatalystInstance() {
1113
+      ReactContext reactContext = (ReactContext) this.getContext();
1114
+
1115
+      if (reactContext != null) {
1116
+        mCatalystInstance = reactContext.getCatalystInstance();
1117
+      }
1118
+    }
1119
+
999
     @SuppressLint("AddJavascriptInterface")
1120
     @SuppressLint("AddJavascriptInterface")
1000
     public void setMessagingEnabled(boolean enabled) {
1121
     public void setMessagingEnabled(boolean enabled) {
1001
       if (messagingEnabled == enabled) {
1122
       if (messagingEnabled == enabled) {
1006
 
1127
 
1007
       if (enabled) {
1128
       if (enabled) {
1008
         addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE);
1129
         addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE);
1130
+        this.createCatalystInstance();
1009
       } else {
1131
       } else {
1010
         removeJavascriptInterface(JAVASCRIPT_INTERFACE);
1132
         removeJavascriptInterface(JAVASCRIPT_INTERFACE);
1011
       }
1133
       }
1012
     }
1134
     }
1013
 
1135
 
1136
+    public void setMessagingModuleName(String moduleName) {
1137
+      messagingModuleName = moduleName;
1138
+    }
1139
+
1014
     protected void evaluateJavascriptWithFallback(String script) {
1140
     protected void evaluateJavascriptWithFallback(String script) {
1015
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
1141
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
1016
         evaluateJavascript(script, null);
1142
         evaluateJavascript(script, null);
1034
     }
1160
     }
1035
 
1161
 
1036
     public void onMessage(String message) {
1162
     public void onMessage(String message) {
1163
+      ReactContext reactContext = (ReactContext) this.getContext();
1164
+      RNCWebView mContext = this;
1165
+
1037
       if (mRNCWebViewClient != null) {
1166
       if (mRNCWebViewClient != null) {
1038
         WebView webView = this;
1167
         WebView webView = this;
1039
         webView.post(new Runnable() {
1168
         webView.post(new Runnable() {
1044
             }
1173
             }
1045
             WritableMap data = mRNCWebViewClient.createWebViewEvent(webView, webView.getUrl());
1174
             WritableMap data = mRNCWebViewClient.createWebViewEvent(webView, webView.getUrl());
1046
             data.putString("data", message);
1175
             data.putString("data", message);
1047
-            dispatchEvent(webView, new TopMessageEvent(webView.getId(), data));
1176
+
1177
+            if (mCatalystInstance != null) {
1178
+              mContext.sendDirectMessage(data);
1179
+            } else {
1180
+              dispatchEvent(webView, new TopMessageEvent(webView.getId(), data));
1181
+            }
1048
           }
1182
           }
1049
         });
1183
         });
1050
       } else {
1184
       } else {
1051
         WritableMap eventData = Arguments.createMap();
1185
         WritableMap eventData = Arguments.createMap();
1052
         eventData.putString("data", message);
1186
         eventData.putString("data", message);
1053
-        dispatchEvent(this, new TopMessageEvent(this.getId(), eventData));
1187
+
1188
+        if (mCatalystInstance != null) {
1189
+          this.sendDirectMessage(eventData);
1190
+        } else {
1191
+          dispatchEvent(this, new TopMessageEvent(this.getId(), eventData));
1192
+        }
1054
       }
1193
       }
1055
     }
1194
     }
1056
 
1195
 
1196
+    protected void sendDirectMessage(WritableMap data) {
1197
+      WritableNativeMap event = new WritableNativeMap();
1198
+      event.putMap("nativeEvent", data);
1199
+
1200
+      WritableNativeArray params = new WritableNativeArray();
1201
+      params.pushMap(event);
1202
+
1203
+      mCatalystInstance.callFunction(messagingModuleName, "onMessage", params);
1204
+    }
1205
+
1057
     protected void onScrollChanged(int x, int y, int oldX, int oldY) {
1206
     protected void onScrollChanged(int x, int y, int oldX, int oldY) {
1058
       super.onScrollChanged(x, y, oldX, oldY);
1207
       super.onScrollChanged(x, y, oldX, oldY);
1059
 
1208
 
1087
       destroy();
1236
       destroy();
1088
     }
1237
     }
1089
 
1238
 
1239
+    @Override
1240
+    public void destroy() {
1241
+      if (mWebChromeClient != null) {
1242
+        mWebChromeClient.onHideCustomView();
1243
+      }
1244
+      super.destroy();
1245
+    }
1246
+
1090
     protected class RNCWebViewBridge {
1247
     protected class RNCWebViewBridge {
1091
       RNCWebView mContext;
1248
       RNCWebView mContext;
1092
 
1249
 
1103
         mContext.onMessage(message);
1260
         mContext.onMessage(message);
1104
       }
1261
       }
1105
     }
1262
     }
1263
+
1264
+    protected static class ProgressChangedFilter {
1265
+      private boolean waitingForCommandLoadUrl = false;
1266
+
1267
+      public void setWaitingForCommandLoadUrl(boolean isWaiting) {
1268
+        waitingForCommandLoadUrl = isWaiting;
1269
+      }
1270
+
1271
+      public boolean isWaitingForCommandLoadUrl() {
1272
+        return waitingForCommandLoadUrl;
1273
+      }
1274
+    }
1106
   }
1275
   }
1107
 }
1276
 }

+ 174
- 75
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java View File

11
 import android.os.Environment;
11
 import android.os.Environment;
12
 import android.os.Parcelable;
12
 import android.os.Parcelable;
13
 import android.provider.MediaStore;
13
 import android.provider.MediaStore;
14
+
14
 import androidx.annotation.RequiresApi;
15
 import androidx.annotation.RequiresApi;
15
 import androidx.core.content.ContextCompat;
16
 import androidx.core.content.ContextCompat;
16
 import androidx.core.content.FileProvider;
17
 import androidx.core.content.FileProvider;
18
+
17
 import android.util.Log;
19
 import android.util.Log;
18
 import android.webkit.MimeTypeMap;
20
 import android.webkit.MimeTypeMap;
19
 import android.webkit.ValueCallback;
21
 import android.webkit.ValueCallback;
32
 import java.io.File;
34
 import java.io.File;
33
 import java.io.IOException;
35
 import java.io.IOException;
34
 import java.util.ArrayList;
36
 import java.util.ArrayList;
37
+import java.util.Arrays;
35
 
38
 
36
 import static android.app.Activity.RESULT_OK;
39
 import static android.app.Activity.RESULT_OK;
37
 
40
 
41
   private static final int PICKER = 1;
44
   private static final int PICKER = 1;
42
   private static final int PICKER_LEGACY = 3;
45
   private static final int PICKER_LEGACY = 3;
43
   private static final int FILE_DOWNLOAD_PERMISSION_REQUEST = 1;
46
   private static final int FILE_DOWNLOAD_PERMISSION_REQUEST = 1;
44
-  final String DEFAULT_MIME_TYPES = "*/*";
45
   private ValueCallback<Uri> filePathCallbackLegacy;
47
   private ValueCallback<Uri> filePathCallbackLegacy;
46
   private ValueCallback<Uri[]> filePathCallback;
48
   private ValueCallback<Uri[]> filePathCallback;
47
-  private Uri outputFileUri;
49
+  private File outputImage;
50
+  private File outputVideo;
48
   private DownloadManager.Request downloadRequest;
51
   private DownloadManager.Request downloadRequest;
52
+
53
+  private enum MimeType {
54
+    DEFAULT("*/*"),
55
+    IMAGE("image"),
56
+    VIDEO("video");
57
+
58
+    private final String value;
59
+
60
+    MimeType(String value) {
61
+      this.value = value;
62
+    }
63
+  }
64
+
49
   private PermissionListener webviewFileDownloaderPermissionListener = new PermissionListener() {
65
   private PermissionListener webviewFileDownloaderPermissionListener = new PermissionListener() {
50
     @Override
66
     @Override
51
     public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
67
     public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
95
       return;
111
       return;
96
     }
112
     }
97
 
113
 
114
+    boolean imageTaken = false;
115
+    boolean videoTaken = false;
116
+
117
+    if (outputImage != null && outputImage.length() > 0) {
118
+      imageTaken = true;
119
+    }
120
+    if (outputVideo != null && outputVideo.length() > 0) {
121
+      videoTaken = true;
122
+    }
123
+
98
     // based off of which button was pressed, we get an activity result and a file
124
     // based off of which button was pressed, we get an activity result and a file
99
     // the camera activity doesn't properly return the filename* (I think?) so we use
125
     // the camera activity doesn't properly return the filename* (I think?) so we use
100
     // this filename instead
126
     // this filename instead
105
             filePathCallback.onReceiveValue(null);
131
             filePathCallback.onReceiveValue(null);
106
           }
132
           }
107
         } else {
133
         } else {
108
-          Uri result[] = this.getSelectedFiles(data, resultCode);
109
-          if (result != null) {
110
-            filePathCallback.onReceiveValue(result);
134
+          if (imageTaken) {
135
+            filePathCallback.onReceiveValue(new Uri[]{getOutputUri(outputImage)});
136
+          } else if (videoTaken) {
137
+            filePathCallback.onReceiveValue(new Uri[]{getOutputUri(outputVideo)});
111
           } else {
138
           } else {
112
-            filePathCallback.onReceiveValue(new Uri[]{outputFileUri});
139
+            filePathCallback.onReceiveValue(this.getSelectedFiles(data, resultCode));
113
           }
140
           }
114
         }
141
         }
115
         break;
142
         break;
116
       case PICKER_LEGACY:
143
       case PICKER_LEGACY:
117
-        Uri result = resultCode != Activity.RESULT_OK ? null : data == null ? outputFileUri : data.getData();
118
-        filePathCallbackLegacy.onReceiveValue(result);
144
+        if (resultCode != RESULT_OK) {
145
+          filePathCallbackLegacy.onReceiveValue(null);
146
+        } else {
147
+          if (imageTaken) {
148
+            filePathCallbackLegacy.onReceiveValue(getOutputUri(outputImage));
149
+          } else if (videoTaken) {
150
+            filePathCallbackLegacy.onReceiveValue(getOutputUri(outputVideo));
151
+          } else {
152
+            filePathCallbackLegacy.onReceiveValue(data.getData());
153
+          }
154
+        }
119
         break;
155
         break;
120
 
156
 
121
     }
157
     }
158
+
159
+    if (outputImage != null && !imageTaken) {
160
+      outputImage.delete();
161
+    }
162
+    if (outputVideo != null && !videoTaken) {
163
+      outputVideo.delete();
164
+    }
165
+
122
     filePathCallback = null;
166
     filePathCallback = null;
123
     filePathCallbackLegacy = null;
167
     filePathCallbackLegacy = null;
124
-    outputFileUri = null;
168
+    outputImage = null;
169
+    outputVideo = null;
125
   }
170
   }
126
 
171
 
127
   public void onNewIntent(Intent intent) {
172
   public void onNewIntent(Intent intent) {
132
       return null;
177
       return null;
133
     }
178
     }
134
 
179
 
135
-    // we have one file selected
136
-    if (data.getData() != null) {
137
-      if (resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
138
-        return WebChromeClient.FileChooserParams.parseResult(resultCode, data);
139
-      } else {
140
-        return null;
141
-      }
142
-    }
143
-
144
     // we have multiple files selected
180
     // we have multiple files selected
145
     if (data.getClipData() != null) {
181
     if (data.getClipData() != null) {
146
       final int numSelectedFiles = data.getClipData().getItemCount();
182
       final int numSelectedFiles = data.getClipData().getItemCount();
150
       }
186
       }
151
       return result;
187
       return result;
152
     }
188
     }
189
+
190
+    // we have one file selected
191
+    if (data.getData() != null && resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
192
+      return WebChromeClient.FileChooserParams.parseResult(resultCode, data);
193
+    }
194
+
153
     return null;
195
     return null;
154
   }
196
   }
155
 
197
 
161
 
203
 
162
     ArrayList<Parcelable> extraIntents = new ArrayList<>();
204
     ArrayList<Parcelable> extraIntents = new ArrayList<>();
163
     if (acceptsImages(acceptType)) {
205
     if (acceptsImages(acceptType)) {
164
-      extraIntents.add(getPhotoIntent());
206
+      Intent photoIntent = getPhotoIntent();
207
+      if (photoIntent != null) {
208
+        extraIntents.add(photoIntent);
209
+      }
165
     }
210
     }
166
     if (acceptsVideo(acceptType)) {
211
     if (acceptsVideo(acceptType)) {
167
-      extraIntents.add(getVideoIntent());
212
+      Intent videoIntent = getVideoIntent();
213
+      if (videoIntent != null) {
214
+        extraIntents.add(videoIntent);
215
+      }
168
     }
216
     }
169
     chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{}));
217
     chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{}));
170
 
218
 
176
   }
224
   }
177
 
225
 
178
   @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
226
   @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
179
-  public boolean startPhotoPickerIntent(final ValueCallback<Uri[]> callback, final Intent intent, final String[] acceptTypes, final boolean allowMultiple) {
227
+  public boolean startPhotoPickerIntent(final ValueCallback<Uri[]> callback, final String[] acceptTypes, final boolean allowMultiple) {
180
     filePathCallback = callback;
228
     filePathCallback = callback;
181
 
229
 
182
     ArrayList<Parcelable> extraIntents = new ArrayList<>();
230
     ArrayList<Parcelable> extraIntents = new ArrayList<>();
183
-    if (acceptsImages(acceptTypes)) {
184
-      extraIntents.add(getPhotoIntent());
185
-    }
186
-    if (acceptsVideo(acceptTypes)) {
187
-      extraIntents.add(getVideoIntent());
231
+    if (!needsCameraPermission()) {
232
+      if (acceptsImages(acceptTypes)) {
233
+        Intent photoIntent = getPhotoIntent();
234
+        if (photoIntent != null) {
235
+          extraIntents.add(photoIntent);
236
+        }
237
+      }
238
+      if (acceptsVideo(acceptTypes)) {
239
+        Intent videoIntent = getVideoIntent();
240
+        if (videoIntent != null) {
241
+          extraIntents.add(videoIntent);
242
+        }
243
+      }
188
     }
244
     }
189
 
245
 
190
     Intent fileSelectionIntent = getFileChooserIntent(acceptTypes, allowMultiple);
246
     Intent fileSelectionIntent = getFileChooserIntent(acceptTypes, allowMultiple);
216
   }
272
   }
217
 
273
 
218
   public boolean grantFileDownloaderPermissions() {
274
   public boolean grantFileDownloaderPermissions() {
219
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
275
+    // Permission not required for Android Q and above
276
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
220
       return true;
277
       return true;
221
     }
278
     }
222
 
279
 
223
-    boolean result = true;
224
-    if (ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
225
-      result = false;
226
-    }
227
-
228
-    if (!result) {
280
+    boolean result = ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
281
+    if (!result && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
229
       PermissionAwareActivity activity = getPermissionAwareActivity();
282
       PermissionAwareActivity activity = getPermissionAwareActivity();
230
       activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, FILE_DOWNLOAD_PERMISSION_REQUEST, webviewFileDownloaderPermissionListener);
283
       activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, FILE_DOWNLOAD_PERMISSION_REQUEST, webviewFileDownloaderPermissionListener);
231
     }
284
     }
233
     return result;
286
     return result;
234
   }
287
   }
235
 
288
 
289
+  protected boolean needsCameraPermission() {
290
+    boolean needed = false;
291
+
292
+    PackageManager packageManager = getCurrentActivity().getPackageManager();
293
+    try {
294
+      String[] requestedPermissions = packageManager.getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
295
+      if (Arrays.asList(requestedPermissions).contains(Manifest.permission.CAMERA)
296
+        && ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
297
+        needed = true;
298
+      }
299
+    } catch (PackageManager.NameNotFoundException e) {
300
+      needed = true;
301
+    }
302
+
303
+    return needed;
304
+  }
305
+
236
   private Intent getPhotoIntent() {
306
   private Intent getPhotoIntent() {
237
-    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
238
-    outputFileUri = getOutputUri(MediaStore.ACTION_IMAGE_CAPTURE);
239
-    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
307
+    Intent intent = null;
308
+
309
+    try {
310
+      outputImage = getCapturedFile(MimeType.IMAGE);
311
+      Uri outputImageUri = getOutputUri(outputImage);
312
+      intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
313
+      intent.putExtra(MediaStore.EXTRA_OUTPUT, outputImageUri);
314
+    } catch (IOException | IllegalArgumentException e) {
315
+      Log.e("CREATE FILE", "Error occurred while creating the File", e);
316
+      e.printStackTrace();
317
+    }
318
+
240
     return intent;
319
     return intent;
241
   }
320
   }
242
 
321
 
243
   private Intent getVideoIntent() {
322
   private Intent getVideoIntent() {
244
-    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
245
-    // @todo from experience, for Videos we get the data onActivityResult
246
-    // so there's no need to store the Uri
247
-    outputFileUri = getOutputUri(MediaStore.ACTION_VIDEO_CAPTURE);
248
-    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
323
+    Intent intent = null;
324
+
325
+    try {
326
+      outputVideo = getCapturedFile(MimeType.VIDEO);
327
+      Uri outputVideoUri = getOutputUri(outputVideo);
328
+      intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
329
+      intent.putExtra(MediaStore.EXTRA_OUTPUT, outputVideoUri);
330
+    } catch (IOException | IllegalArgumentException e) {
331
+      Log.e("CREATE FILE", "Error occurred while creating the File", e);
332
+      e.printStackTrace();
333
+    }
334
+    
249
     return intent;
335
     return intent;
250
   }
336
   }
251
 
337
 
252
   private Intent getFileChooserIntent(String acceptTypes) {
338
   private Intent getFileChooserIntent(String acceptTypes) {
253
     String _acceptTypes = acceptTypes;
339
     String _acceptTypes = acceptTypes;
254
     if (acceptTypes.isEmpty()) {
340
     if (acceptTypes.isEmpty()) {
255
-      _acceptTypes = DEFAULT_MIME_TYPES;
341
+      _acceptTypes = MimeType.DEFAULT.value;
256
     }
342
     }
257
     if (acceptTypes.matches("\\.\\w+")) {
343
     if (acceptTypes.matches("\\.\\w+")) {
258
       _acceptTypes = getMimeTypeFromExtension(acceptTypes.replace(".", ""));
344
       _acceptTypes = getMimeTypeFromExtension(acceptTypes.replace(".", ""));
266
   private Intent getFileChooserIntent(String[] acceptTypes, boolean allowMultiple) {
352
   private Intent getFileChooserIntent(String[] acceptTypes, boolean allowMultiple) {
267
     Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
353
     Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
268
     intent.addCategory(Intent.CATEGORY_OPENABLE);
354
     intent.addCategory(Intent.CATEGORY_OPENABLE);
269
-    intent.setType("*/*");
355
+    intent.setType(MimeType.DEFAULT.value);
270
     intent.putExtra(Intent.EXTRA_MIME_TYPES, getAcceptedMimeType(acceptTypes));
356
     intent.putExtra(Intent.EXTRA_MIME_TYPES, getAcceptedMimeType(acceptTypes));
271
     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple);
357
     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple);
272
     return intent;
358
     return intent;
277
     if (types.matches("\\.\\w+")) {
363
     if (types.matches("\\.\\w+")) {
278
       mimeType = getMimeTypeFromExtension(types.replace(".", ""));
364
       mimeType = getMimeTypeFromExtension(types.replace(".", ""));
279
     }
365
     }
280
-    return mimeType.isEmpty() || mimeType.toLowerCase().contains("image");
366
+    return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.IMAGE.value);
281
   }
367
   }
282
 
368
 
283
   private Boolean acceptsImages(String[] types) {
369
   private Boolean acceptsImages(String[] types) {
284
     String[] mimeTypes = getAcceptedMimeType(types);
370
     String[] mimeTypes = getAcceptedMimeType(types);
285
-    return isArrayEmpty(mimeTypes) || arrayContainsString(mimeTypes, "image");
371
+    return arrayContainsString(mimeTypes, MimeType.DEFAULT.value) || arrayContainsString(mimeTypes, MimeType.IMAGE.value);
286
   }
372
   }
287
 
373
 
288
   private Boolean acceptsVideo(String types) {
374
   private Boolean acceptsVideo(String types) {
375
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
376
+      return false;
377
+    }
378
+
289
     String mimeType = types;
379
     String mimeType = types;
290
     if (types.matches("\\.\\w+")) {
380
     if (types.matches("\\.\\w+")) {
291
       mimeType = getMimeTypeFromExtension(types.replace(".", ""));
381
       mimeType = getMimeTypeFromExtension(types.replace(".", ""));
292
     }
382
     }
293
-    return mimeType.isEmpty() || mimeType.toLowerCase().contains("video");
383
+    return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.VIDEO.value);
294
   }
384
   }
295
 
385
 
296
   private Boolean acceptsVideo(String[] types) {
386
   private Boolean acceptsVideo(String[] types) {
387
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
388
+      return false;
389
+    }
390
+
297
     String[] mimeTypes = getAcceptedMimeType(types);
391
     String[] mimeTypes = getAcceptedMimeType(types);
298
-    return isArrayEmpty(mimeTypes) || arrayContainsString(mimeTypes, "video");
392
+    return arrayContainsString(mimeTypes, MimeType.DEFAULT.value) || arrayContainsString(mimeTypes, MimeType.VIDEO.value);
299
   }
393
   }
300
 
394
 
301
   private Boolean arrayContainsString(String[] array, String pattern) {
395
   private Boolean arrayContainsString(String[] array, String pattern) {
308
   }
402
   }
309
 
403
 
310
   private String[] getAcceptedMimeType(String[] types) {
404
   private String[] getAcceptedMimeType(String[] types) {
311
-    if (isArrayEmpty(types)) {
312
-      return new String[]{DEFAULT_MIME_TYPES};
405
+    if (noAcceptTypesSet(types)) {
406
+      return new String[]{MimeType.DEFAULT.value};
313
     }
407
     }
314
     String[] mimeTypes = new String[types.length];
408
     String[] mimeTypes = new String[types.length];
315
     for (int i = 0; i < types.length; i++) {
409
     for (int i = 0; i < types.length; i++) {
317
       // convert file extensions to mime types
411
       // convert file extensions to mime types
318
       if (t.matches("\\.\\w+")) {
412
       if (t.matches("\\.\\w+")) {
319
         String mimeType = getMimeTypeFromExtension(t.replace(".", ""));
413
         String mimeType = getMimeTypeFromExtension(t.replace(".", ""));
320
-        mimeTypes[i] = mimeType;
414
+        if(mimeType != null) {
415
+          mimeTypes[i] = mimeType;
416
+        } else {
417
+          mimeTypes[i] = t;
418
+        }
321
       } else {
419
       } else {
322
         mimeTypes[i] = t;
420
         mimeTypes[i] = t;
323
       }
421
       }
333
     return type;
431
     return type;
334
   }
432
   }
335
 
433
 
336
-  private Uri getOutputUri(String intentType) {
337
-    File capturedFile = null;
338
-    try {
339
-      capturedFile = getCapturedFile(intentType);
340
-    } catch (IOException e) {
341
-      Log.e("CREATE FILE", "Error occurred while creating the File", e);
342
-      e.printStackTrace();
343
-    }
344
-
434
+  private Uri getOutputUri(File capturedFile) {
345
     // for versions below 6.0 (23) we use the old File creation & permissions model
435
     // for versions below 6.0 (23) we use the old File creation & permissions model
346
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
436
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
347
       return Uri.fromFile(capturedFile);
437
       return Uri.fromFile(capturedFile);
352
     return FileProvider.getUriForFile(getReactApplicationContext(), packageName + ".fileprovider", capturedFile);
442
     return FileProvider.getUriForFile(getReactApplicationContext(), packageName + ".fileprovider", capturedFile);
353
   }
443
   }
354
 
444
 
355
-  private File getCapturedFile(String intentType) throws IOException {
445
+  private File getCapturedFile(MimeType mimeType) throws IOException {
356
     String prefix = "";
446
     String prefix = "";
357
     String suffix = "";
447
     String suffix = "";
358
     String dir = "";
448
     String dir = "";
359
-    String filename = "";
360
 
449
 
361
-    if (intentType.equals(MediaStore.ACTION_IMAGE_CAPTURE)) {
362
-      prefix = "image-";
363
-      suffix = ".jpg";
364
-      dir = Environment.DIRECTORY_PICTURES;
365
-    } else if (intentType.equals(MediaStore.ACTION_VIDEO_CAPTURE)) {
366
-      prefix = "video-";
367
-      suffix = ".mp4";
368
-      dir = Environment.DIRECTORY_MOVIES;
450
+    switch (mimeType) {
451
+      case IMAGE:
452
+        prefix = "image-";
453
+        suffix = ".jpg";
454
+        dir = Environment.DIRECTORY_PICTURES;
455
+        break;
456
+      case VIDEO:
457
+        prefix = "video-";
458
+        suffix = ".mp4";
459
+        dir = Environment.DIRECTORY_MOVIES;
460
+        break;
461
+
462
+      default:
463
+        break;
369
     }
464
     }
370
 
465
 
371
-    filename = prefix + String.valueOf(System.currentTimeMillis()) + suffix;
466
+    String filename = prefix + String.valueOf(System.currentTimeMillis()) + suffix;
467
+    File outputFile = null;
372
 
468
 
373
     // for versions below 6.0 (23) we use the old File creation & permissions model
469
     // for versions below 6.0 (23) we use the old File creation & permissions model
374
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
470
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
375
       // only this Directory works on all tested Android versions
471
       // only this Directory works on all tested Android versions
376
       // ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21)
472
       // ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21)
377
       File storageDir = Environment.getExternalStoragePublicDirectory(dir);
473
       File storageDir = Environment.getExternalStoragePublicDirectory(dir);
378
-      return new File(storageDir, filename);
474
+      outputFile = new File(storageDir, filename);
475
+    } else {
476
+      File storageDir = getReactApplicationContext().getExternalFilesDir(null);
477
+      outputFile = File.createTempFile(prefix, suffix, storageDir);
379
     }
478
     }
380
 
479
 
381
-    File storageDir = getReactApplicationContext().getExternalFilesDir(null);
382
-    return File.createTempFile(filename, suffix, storageDir);
480
+    return outputFile;
383
   }
481
   }
384
 
482
 
385
-  private Boolean isArrayEmpty(String[] arr) {
483
+  private Boolean noAcceptTypesSet(String[] types) {
386
     // when our array returned from getAcceptTypes() has no values set from the webview
484
     // when our array returned from getAcceptTypes() has no values set from the webview
387
     // i.e. <input type="file" />, without any "accept" attr
485
     // i.e. <input type="file" />, without any "accept" attr
388
     // will be an array with one empty string element, afaik
486
     // will be an array with one empty string element, afaik
389
-    return arr.length == 0 || (arr.length == 1 && arr[0].length() == 0);
487
+
488
+    return types.length == 0 || (types.length == 1 && types[0] != null && types[0].length() == 0);
390
   }
489
   }
391
 
490
 
392
   private PermissionAwareActivity getPermissionAwareActivity() {
491
   private PermissionAwareActivity getPermissionAwareActivity() {

+ 0
- 27
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java View File

1
-package com.reactnativecommunity.webview;
2
-
3
-import com.facebook.react.ReactPackage;
4
-import com.facebook.react.bridge.JavaScriptModule;
5
-import com.facebook.react.bridge.NativeModule;
6
-import com.facebook.react.bridge.ReactApplicationContext;
7
-import com.facebook.react.uimanager.ViewManager;
8
-
9
-import java.util.Collections;
10
-import java.util.List;
11
-
12
-public class RNCWebViewPackage implements ReactPackage {
13
-  @Override
14
-  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
15
-    return Collections.singletonList(new RNCWebViewModule(reactContext));
16
-  }
17
-
18
-  // Deprecated from RN 0.47
19
-  public List<Class<? extends JavaScriptModule>> createJSModules() {
20
-    return Collections.emptyList();
21
-  }
22
-
23
-  @Override
24
-  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
25
-    return Collections.singletonList(new RNCWebViewManager());
26
-  }
27
-}

+ 15
- 0
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt View File

1
+package com.reactnativecommunity.webview
2
+
3
+import com.facebook.react.ReactPackage
4
+import com.facebook.react.bridge.ReactApplicationContext
5
+
6
+
7
+class RNCWebViewPackage: ReactPackage {
8
+  override fun createNativeModules(reactContext: ReactApplicationContext) = listOf(
9
+    RNCWebViewModule(reactContext)
10
+  )
11
+
12
+  override fun createViewManagers(reactContext: ReactApplicationContext) = listOf(
13
+    RNCWebViewManager()
14
+  )
15
+}

ios/RNCWKProcessPoolManager.h → apple/RNCWKProcessPoolManager.h View File


ios/RNCWKProcessPoolManager.m → apple/RNCWKProcessPoolManager.m View File


ios/RNCWebView.h → apple/RNCWebView.h View File

19
 
19
 
20
 @end
20
 @end
21
 
21
 
22
+@interface RNCWeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
23
+@property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
24
+- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
25
+@end
26
+
22
 @interface RNCWebView : RCTView
27
 @interface RNCWebView : RCTView
23
 
28
 
24
 @property (nonatomic, weak) id<RNCWebViewDelegate> _Nullable delegate;
29
 @property (nonatomic, weak) id<RNCWebViewDelegate> _Nullable delegate;
25
 @property (nonatomic, copy) NSDictionary * _Nullable source;
30
 @property (nonatomic, copy) NSDictionary * _Nullable source;
26
 @property (nonatomic, assign) BOOL messagingEnabled;
31
 @property (nonatomic, assign) BOOL messagingEnabled;
27
 @property (nonatomic, copy) NSString * _Nullable injectedJavaScript;
32
 @property (nonatomic, copy) NSString * _Nullable injectedJavaScript;
33
+@property (nonatomic, copy) NSString * _Nullable injectedJavaScriptBeforeContentLoaded;
34
+@property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly;
35
+@property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly;
28
 @property (nonatomic, assign) BOOL scrollEnabled;
36
 @property (nonatomic, assign) BOOL scrollEnabled;
29
 @property (nonatomic, assign) BOOL sharedCookiesEnabled;
37
 @property (nonatomic, assign) BOOL sharedCookiesEnabled;
30
 @property (nonatomic, assign) BOOL autoManageStatusBarEnabled;
38
 @property (nonatomic, assign) BOOL autoManageStatusBarEnabled;
47
 @property (nonatomic, copy) NSString * _Nullable applicationNameForUserAgent;
55
 @property (nonatomic, copy) NSString * _Nullable applicationNameForUserAgent;
48
 @property (nonatomic, assign) BOOL cacheEnabled;
56
 @property (nonatomic, assign) BOOL cacheEnabled;
49
 @property (nonatomic, assign) BOOL javaScriptEnabled;
57
 @property (nonatomic, assign) BOOL javaScriptEnabled;
58
+@property (nonatomic, assign) BOOL javaScriptCanOpenWindowsAutomatically;
59
+@property (nonatomic, assign) BOOL allowFileAccessFromFileURLs;
50
 @property (nonatomic, assign) BOOL allowsLinkPreview;
60
 @property (nonatomic, assign) BOOL allowsLinkPreview;
51
 @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
61
 @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
52
 @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
62
 @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
53
 @property (nonatomic, assign) BOOL directionalLockEnabled;
63
 @property (nonatomic, assign) BOOL directionalLockEnabled;
64
+@property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch;
54
 @property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
65
 @property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL;
55
 
66
 
56
 + (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
67
 + (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;

ios/RNCWebView.m → apple/RNCWebView.m View File

9
 #import <React/RCTConvert.h>
9
 #import <React/RCTConvert.h>
10
 #import <React/RCTAutoInsetsProtocol.h>
10
 #import <React/RCTAutoInsetsProtocol.h>
11
 #import "RNCWKProcessPoolManager.h"
11
 #import "RNCWKProcessPoolManager.h"
12
+#if !TARGET_OS_OSX
12
 #import <UIKit/UIKit.h>
13
 #import <UIKit/UIKit.h>
14
+#else
15
+#import <React/RCTUIKit.h>
16
+#endif // !TARGET_OS_OSX
13
 
17
 
14
 #import "objc/runtime.h"
18
 #import "objc/runtime.h"
15
 
19
 
16
 static NSTimer *keyboardTimer;
20
 static NSTimer *keyboardTimer;
21
+static NSString *const HistoryShimName = @"ReactNativeHistoryShim";
17
 static NSString *const MessageHandlerName = @"ReactNativeWebView";
22
 static NSString *const MessageHandlerName = @"ReactNativeWebView";
18
 static NSURLCredential* clientAuthenticationCredential;
23
 static NSURLCredential* clientAuthenticationCredential;
19
 static NSDictionary* customCertificatesForHost;
24
 static NSDictionary* customCertificatesForHost;
20
 
25
 
26
+#if !TARGET_OS_OSX
21
 // runtime trick to remove WKWebView keyboard default toolbar
27
 // runtime trick to remove WKWebView keyboard default toolbar
22
 // see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279
28
 // see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279
23
-@interface _SwizzleHelperWK : NSObject @end
29
+@interface _SwizzleHelperWK : UIView
30
+@property (nonatomic, copy) WKWebView *webView;
31
+@end
24
 @implementation _SwizzleHelperWK
32
 @implementation _SwizzleHelperWK
25
 -(id)inputAccessoryView
33
 -(id)inputAccessoryView
26
 {
34
 {
27
-  return nil;
35
+    if (_webView == nil) {
36
+        return nil;
37
+    }
38
+
39
+    if ([_webView respondsToSelector:@selector(inputAssistantItem)]) {
40
+        UITextInputAssistantItem *inputAssistantItem = [_webView inputAssistantItem];
41
+        inputAssistantItem.leadingBarButtonGroups = @[];
42
+        inputAssistantItem.trailingBarButtonGroups = @[];
43
+    }
44
+    return nil;
45
+}
46
+@end
47
+#endif // !TARGET_OS_OSX
48
+
49
+#if TARGET_OS_OSX
50
+@interface RNCWKWebView : WKWebView
51
+@end
52
+@implementation RNCWKWebView
53
+- (void)scrollWheel:(NSEvent *)theEvent {
54
+  RNCWebView *rncWebView = (RNCWebView *)[self superview];
55
+  RCTAssert([rncWebView isKindOfClass:[rncWebView class]], @"superview must be an RNCWebView");
56
+  if (![rncWebView scrollEnabled]) {
57
+    [[self nextResponder] scrollWheel:theEvent];
58
+    return;
59
+  }
60
+  [super scrollWheel:theEvent];
28
 }
61
 }
29
 @end
62
 @end
63
+#endif // TARGET_OS_OSX
64
+
65
+@interface RNCWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler,
66
+#if !TARGET_OS_OSX
67
+    UIScrollViewDelegate,
68
+#endif // !TARGET_OS_OSX
69
+    RCTAutoInsetsProtocol>
30
 
70
 
31
-@interface RNCWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIScrollViewDelegate, RCTAutoInsetsProtocol>
71
+@property (nonatomic, copy) RCTDirectEventBlock onFileDownload;
32
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
72
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
33
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
73
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
34
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
74
 @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
38
 @property (nonatomic, copy) RCTDirectEventBlock onMessage;
78
 @property (nonatomic, copy) RCTDirectEventBlock onMessage;
39
 @property (nonatomic, copy) RCTDirectEventBlock onScroll;
79
 @property (nonatomic, copy) RCTDirectEventBlock onScroll;
40
 @property (nonatomic, copy) RCTDirectEventBlock onContentProcessDidTerminate;
80
 @property (nonatomic, copy) RCTDirectEventBlock onContentProcessDidTerminate;
81
+#if !TARGET_OS_OSX
41
 @property (nonatomic, copy) WKWebView *webView;
82
 @property (nonatomic, copy) WKWebView *webView;
83
+#else
84
+@property (nonatomic, copy) RNCWKWebView *webView;
85
+#endif // !TARGET_OS_OSX
86
+@property (nonatomic, strong) WKUserScript *postMessageScript;
87
+@property (nonatomic, strong) WKUserScript *atStartScript;
88
+@property (nonatomic, strong) WKUserScript *atEndScript;
42
 @end
89
 @end
43
 
90
 
44
 @implementation RNCWebView
91
 @implementation RNCWebView
45
 {
92
 {
93
+#if !TARGET_OS_OSX
46
   UIColor * _savedBackgroundColor;
94
   UIColor * _savedBackgroundColor;
95
+#else
96
+  RCTUIColor * _savedBackgroundColor;
97
+#endif // !TARGET_OS_OSX
47
   BOOL _savedHideKeyboardAccessoryView;
98
   BOOL _savedHideKeyboardAccessoryView;
48
   BOOL _savedKeyboardDisplayRequiresUserAction;
99
   BOOL _savedKeyboardDisplayRequiresUserAction;
49
 
100
 
50
   // Workaround for StatusBar appearance bug for iOS 12
101
   // Workaround for StatusBar appearance bug for iOS 12
51
   // https://github.com/react-native-community/react-native-webview/issues/62
102
   // https://github.com/react-native-community/react-native-webview/issues/62
52
   BOOL _isFullScreenVideoOpen;
103
   BOOL _isFullScreenVideoOpen;
104
+#if !TARGET_OS_OSX
53
   UIStatusBarStyle _savedStatusBarStyle;
105
   UIStatusBarStyle _savedStatusBarStyle;
106
+#endif // !TARGET_OS_OSX
54
   BOOL _savedStatusBarHidden;
107
   BOOL _savedStatusBarHidden;
55
 
108
 
56
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
109
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
61
 - (instancetype)initWithFrame:(CGRect)frame
114
 - (instancetype)initWithFrame:(CGRect)frame
62
 {
115
 {
63
   if ((self = [super initWithFrame:frame])) {
116
   if ((self = [super initWithFrame:frame])) {
117
+    #if !TARGET_OS_OSX
64
     super.backgroundColor = [UIColor clearColor];
118
     super.backgroundColor = [UIColor clearColor];
119
+    #else
120
+    super.backgroundColor = [RCTUIColor clearColor];
121
+    #endif // !TARGET_OS_OSX
65
     _bounces = YES;
122
     _bounces = YES;
66
     _scrollEnabled = YES;
123
     _scrollEnabled = YES;
67
     _showsHorizontalScrollIndicator = YES;
124
     _showsHorizontalScrollIndicator = YES;
71
     _autoManageStatusBarEnabled = YES;
128
     _autoManageStatusBarEnabled = YES;
72
     _contentInset = UIEdgeInsetsZero;
129
     _contentInset = UIEdgeInsetsZero;
73
     _savedKeyboardDisplayRequiresUserAction = YES;
130
     _savedKeyboardDisplayRequiresUserAction = YES;
131
+    #if !TARGET_OS_OSX
74
     _savedStatusBarStyle = RCTSharedApplication().statusBarStyle;
132
     _savedStatusBarStyle = RCTSharedApplication().statusBarStyle;
75
     _savedStatusBarHidden = RCTSharedApplication().statusBarHidden;
133
     _savedStatusBarHidden = RCTSharedApplication().statusBarHidden;
134
+    #endif // !TARGET_OS_OSX
135
+    _injectedJavaScript = nil;
136
+    _injectedJavaScriptForMainFrameOnly = YES;
137
+    _injectedJavaScriptBeforeContentLoaded = nil;
138
+    _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = YES;
76
 
139
 
77
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
140
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
78
     _savedContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
141
     _savedContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
79
 #endif
142
 #endif
80
   }
143
   }
81
 
144
 
145
+#if !TARGET_OS_OSX
146
+    [[NSNotificationCenter defaultCenter]addObserver:self
147
+    selector:@selector(appDidBecomeActive)
148
+        name:UIApplicationDidBecomeActiveNotification
149
+      object:nil];
150
+
151
+    [[NSNotificationCenter defaultCenter]addObserver:self
152
+    selector:@selector(appWillResignActive)
153
+        name:UIApplicationWillResignActiveNotification
154
+      object:nil];
82
   if (@available(iOS 12.0, *)) {
155
   if (@available(iOS 12.0, *)) {
83
     // Workaround for a keyboard dismissal bug present in iOS 12
156
     // Workaround for a keyboard dismissal bug present in iOS 12
84
     // https://openradar.appspot.com/radar?id=5018321736957952
157
     // https://openradar.appspot.com/radar?id=5018321736957952
93
 
166
 
94
     // Workaround for StatusBar appearance bug for iOS 12
167
     // Workaround for StatusBar appearance bug for iOS 12
95
     // https://github.com/react-native-community/react-native-webview/issues/62
168
     // https://github.com/react-native-community/react-native-webview/issues/62
96
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toggleFullScreenVideoStatusBars) name:@"_MRMediaRemotePlayerSupportedCommandsDidChangeNotification" object:nil];
97
-  }
169
+      [[NSNotificationCenter defaultCenter] addObserver:self
170
+                                               selector:@selector(showFullScreenVideoStatusBars)
171
+                                                   name:UIWindowDidBecomeVisibleNotification
172
+                                                 object:nil];
173
+
174
+      [[NSNotificationCenter defaultCenter] addObserver:self
175
+                                               selector:@selector(hideFullScreenVideoStatusBars)
176
+                                                   name:UIWindowDidBecomeHiddenNotification
177
+                                                 object:nil];
98
 
178
 
179
+  }
180
+#endif // !TARGET_OS_OSX
99
   return self;
181
   return self;
100
 }
182
 }
101
 
183
 
115
   return nil;
197
   return nil;
116
 }
198
 }
117
 
199
 
118
-- (void)didMoveToWindow
200
+- (WKWebViewConfiguration *)setUpWkWebViewConfig
119
 {
201
 {
120
-  if (self.window != nil && _webView == nil) {
121
-    WKWebViewConfiguration *wkWebViewConfig = [WKWebViewConfiguration new];
122
-    WKPreferences *prefs = [[WKPreferences alloc]init];
123
-    if (!_javaScriptEnabled) {
124
-      prefs.javaScriptEnabled = NO;
125
-      wkWebViewConfig.preferences = prefs;
126
-    }
127
-    if (_incognito) {
128
-      wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
129
-    } else if (_cacheEnabled) {
130
-      wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore defaultDataStore];
131
-    }
132
-    if(self.useSharedProcessPool) {
133
-      wkWebViewConfig.processPool = [[RNCWKProcessPoolManager sharedManager] sharedProcessPool];
134
-    }
135
-    wkWebViewConfig.userContentController = [WKUserContentController new];
136
-
137
-    if (_messagingEnabled) {
138
-      [wkWebViewConfig.userContentController addScriptMessageHandler:self name:MessageHandlerName];
139
-
140
-      NSString *source = [NSString stringWithFormat:
141
-        @"window.%@ = {"
142
-         "  postMessage: function (data) {"
143
-         "    window.webkit.messageHandlers.%@.postMessage(String(data));"
144
-         "  }"
145
-         "};", MessageHandlerName, MessageHandlerName
146
-      ];
202
+  WKWebViewConfiguration *wkWebViewConfig = [WKWebViewConfiguration new];
203
+  WKPreferences *prefs = [[WKPreferences alloc]init];
204
+  BOOL _prefsUsed = NO;
205
+  if (!_javaScriptEnabled) {
206
+    prefs.javaScriptEnabled = NO;
207
+    _prefsUsed = YES;
208
+  }
209
+  if (_allowFileAccessFromFileURLs) {
210
+    [prefs setValue:@TRUE forKey:@"allowFileAccessFromFileURLs"];
211
+    _prefsUsed = YES;
212
+  }
213
+  if (_javaScriptCanOpenWindowsAutomatically) {
214
+    [prefs setValue:@TRUE forKey:@"javaScriptCanOpenWindowsAutomatically"];
215
+    _prefsUsed = YES;
216
+  }
217
+  if (_prefsUsed) {
218
+    wkWebViewConfig.preferences = prefs;
219
+  }
220
+  if (_incognito) {
221
+    wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
222
+  } else if (_cacheEnabled) {
223
+    wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore defaultDataStore];
224
+  }
225
+  if(self.useSharedProcessPool) {
226
+    wkWebViewConfig.processPool = [[RNCWKProcessPoolManager sharedManager] sharedProcessPool];
227
+  }
228
+  wkWebViewConfig.userContentController = [WKUserContentController new];
147
 
229
 
148
-      WKUserScript *script = [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
149
-      [wkWebViewConfig.userContentController addUserScript:script];
150
-    }
230
+  // Shim the HTML5 history API:
231
+  [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
232
+                                                            name:HistoryShimName];
233
+  [self resetupScripts:wkWebViewConfig];
151
 
234
 
152
-    wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
235
+#if !TARGET_OS_OSX
236
+  wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
153
 #if WEBKIT_IOS_10_APIS_AVAILABLE
237
 #if WEBKIT_IOS_10_APIS_AVAILABLE
154
-    wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction
155
-      ? WKAudiovisualMediaTypeAll
156
-      : WKAudiovisualMediaTypeNone;
157
-    wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes;
238
+  wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction
239
+    ? WKAudiovisualMediaTypeAll
240
+    : WKAudiovisualMediaTypeNone;
241
+  wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes;
158
 #else
242
 #else
159
-    wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction;
243
+  wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction;
160
 #endif
244
 #endif
245
+#endif // !TARGET_OS_OSX
161
 
246
 
162
-    if (_applicationNameForUserAgent) {
163
-        wkWebViewConfig.applicationNameForUserAgent = [NSString stringWithFormat:@"%@ %@", wkWebViewConfig.applicationNameForUserAgent, _applicationNameForUserAgent];
164
-    }
165
-
166
-    if(_sharedCookiesEnabled) {
167
-      // More info to sending cookies with WKWebView
168
-      // https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
169
-      if (@available(iOS 11.0, *)) {
170
-        // Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies
171
-        // See also https://forums.developer.apple.com/thread/97194
172
-        // check if websiteDataStore has not been initialized before
173
-        if(!_incognito && !_cacheEnabled) {
174
-          wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
175
-        }
176
-        for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
177
-          [wkWebViewConfig.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil];
178
-        }
179
-      } else {
180
-        NSMutableString *script = [NSMutableString string];
181
-
182
-        // Clear all existing cookies in a direct called function. This ensures that no
183
-        // javascript error will break the web content javascript.
184
-        // We keep this code here, if someone requires that Cookies are also removed within the
185
-        // the WebView and want to extends the current sharedCookiesEnabled option with an
186
-        // additional property.
187
-        // Generates JS: document.cookie = "key=; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"
188
-        // for each cookie which is already available in the WebView context.
189
-        /*
190
-        [script appendString:@"(function () {\n"];
191
-        [script appendString:@"  var cookies = document.cookie.split('; ');\n"];
192
-        [script appendString:@"  for (var i = 0; i < cookies.length; i++) {\n"];
193
-        [script appendString:@"    if (cookies[i].indexOf('=') !== -1) {\n"];
194
-        [script appendString:@"      document.cookie = cookies[i].split('=')[0] + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT';\n"];
195
-        [script appendString:@"    }\n"];
196
-        [script appendString:@"  }\n"];
197
-        [script appendString:@"})();\n\n"];
198
-        */
199
-
200
-        // Set cookies in a direct called function. This ensures that no
201
-        // javascript error will break the web content javascript.
202
-          // Generates JS: document.cookie = "key=value; Path=/; Expires=Thu, 01 Jan 20xx 00:00:01 GMT;"
203
-        // for each cookie which is available in the application context.
204
-        [script appendString:@"(function () {\n"];
205
-        for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
206
-          [script appendFormat:@"document.cookie = %@ + '=' + %@",
207
-            RCTJSONStringify(cookie.name, NULL),
208
-            RCTJSONStringify(cookie.value, NULL)];
209
-          if (cookie.path) {
210
-            [script appendFormat:@" + '; Path=' + %@", RCTJSONStringify(cookie.path, NULL)];
211
-          }
212
-          if (cookie.expiresDate) {
213
-            [script appendFormat:@" + '; Expires=' + new Date(%f).toUTCString()",
214
-              cookie.expiresDate.timeIntervalSince1970 * 1000
215
-            ];
216
-          }
217
-          [script appendString:@";\n"];
218
-        }
219
-        [script appendString:@"})();\n"];
247
+  if (_applicationNameForUserAgent) {
248
+      wkWebViewConfig.applicationNameForUserAgent = [NSString stringWithFormat:@"%@ %@", wkWebViewConfig.applicationNameForUserAgent, _applicationNameForUserAgent];
249
+  }
220
 
250
 
221
-        WKUserScript* cookieInScript = [[WKUserScript alloc] initWithSource:script
222
-                                                              injectionTime:WKUserScriptInjectionTimeAtDocumentStart
223
-                                                           forMainFrameOnly:YES];
224
-        [wkWebViewConfig.userContentController addUserScript:cookieInScript];
225
-      }
226
-    }
251
+  return wkWebViewConfig;
252
+}
227
 
253
 
254
+- (void)didMoveToWindow
255
+{
256
+  if (self.window != nil && _webView == nil) {
257
+    WKWebViewConfiguration *wkWebViewConfig = [self setUpWkWebViewConfig];
258
+#if !TARGET_OS_OSX
228
     _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
259
     _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
260
+#else
261
+    _webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
262
+#endif // !TARGET_OS_OSX
263
+
229
     [self setBackgroundColor: _savedBackgroundColor];
264
     [self setBackgroundColor: _savedBackgroundColor];
265
+#if !TARGET_OS_OSX
230
     _webView.scrollView.delegate = self;
266
     _webView.scrollView.delegate = self;
267
+#endif // !TARGET_OS_OSX
231
     _webView.UIDelegate = self;
268
     _webView.UIDelegate = self;
232
     _webView.navigationDelegate = self;
269
     _webView.navigationDelegate = self;
270
+#if !TARGET_OS_OSX
233
     _webView.scrollView.scrollEnabled = _scrollEnabled;
271
     _webView.scrollView.scrollEnabled = _scrollEnabled;
234
     _webView.scrollView.pagingEnabled = _pagingEnabled;
272
     _webView.scrollView.pagingEnabled = _pagingEnabled;
235
     _webView.scrollView.bounces = _bounces;
273
     _webView.scrollView.bounces = _bounces;
236
     _webView.scrollView.showsHorizontalScrollIndicator = _showsHorizontalScrollIndicator;
274
     _webView.scrollView.showsHorizontalScrollIndicator = _showsHorizontalScrollIndicator;
237
     _webView.scrollView.showsVerticalScrollIndicator = _showsVerticalScrollIndicator;
275
     _webView.scrollView.showsVerticalScrollIndicator = _showsVerticalScrollIndicator;
238
     _webView.scrollView.directionalLockEnabled = _directionalLockEnabled;
276
     _webView.scrollView.directionalLockEnabled = _directionalLockEnabled;
277
+#endif // !TARGET_OS_OSX
239
     _webView.allowsLinkPreview = _allowsLinkPreview;
278
     _webView.allowsLinkPreview = _allowsLinkPreview;
240
     [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
279
     [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
241
     _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
280
     _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures;
269
         [_webView.configuration.userContentController removeScriptMessageHandlerForName:MessageHandlerName];
308
         [_webView.configuration.userContentController removeScriptMessageHandlerForName:MessageHandlerName];
270
         [_webView removeObserver:self forKeyPath:@"estimatedProgress"];
309
         [_webView removeObserver:self forKeyPath:@"estimatedProgress"];
271
         [_webView removeFromSuperview];
310
         [_webView removeFromSuperview];
311
+#if !TARGET_OS_OSX
272
         _webView.scrollView.delegate = nil;
312
         _webView.scrollView.delegate = nil;
313
+#endif // !TARGET_OS_OSX
273
         _webView = nil;
314
         _webView = nil;
315
+        if (_onContentProcessDidTerminate) {
316
+          NSMutableDictionary<NSString *, id> *event = [self baseEvent];
317
+          _onContentProcessDidTerminate(event);
318
+        }
274
     }
319
     }
275
 
320
 
276
     [super removeFromSuperview];
321
     [super removeFromSuperview];
277
 }
322
 }
278
 
323
 
279
--(void)toggleFullScreenVideoStatusBars
324
+#if !TARGET_OS_OSX
325
+-(void)showFullScreenVideoStatusBars
280
 {
326
 {
281
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
327
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
282
-  if (!_autoManageStatusBarEnabled) {
283
-    return;
284
-  }
285
-  if (!_isFullScreenVideoOpen) {
328
+    if (!_autoManageStatusBarEnabled) {
329
+      return;
330
+    }
331
+
286
     _isFullScreenVideoOpen = YES;
332
     _isFullScreenVideoOpen = YES;
287
     RCTUnsafeExecuteOnMainQueueSync(^{
333
     RCTUnsafeExecuteOnMainQueueSync(^{
288
       [RCTSharedApplication() setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
334
       [RCTSharedApplication() setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
289
     });
335
     });
290
-  } else {
336
+#pragma clang diagnostic pop
337
+}
338
+
339
+-(void)hideFullScreenVideoStatusBars
340
+{
341
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
291
     _isFullScreenVideoOpen = NO;
342
     _isFullScreenVideoOpen = NO;
292
     RCTUnsafeExecuteOnMainQueueSync(^{
343
     RCTUnsafeExecuteOnMainQueueSync(^{
293
       [RCTSharedApplication() setStatusBarHidden:self->_savedStatusBarHidden animated:YES];
344
       [RCTSharedApplication() setStatusBarHidden:self->_savedStatusBarHidden animated:YES];
294
       [RCTSharedApplication() setStatusBarStyle:self->_savedStatusBarStyle animated:YES];
345
       [RCTSharedApplication() setStatusBarStyle:self->_savedStatusBarStyle animated:YES];
295
     });
346
     });
296
-  }
297
 #pragma clang diagnostic pop
347
 #pragma clang diagnostic pop
298
 }
348
 }
299
 
349
 
323
       }];
373
       }];
324
     }
374
     }
325
 }
375
 }
376
+#endif // !TARGET_OS_OSX
326
 
377
 
327
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
378
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
328
     if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
379
     if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
336
     }
387
     }
337
 }
388
 }
338
 
389
 
390
+#if !TARGET_OS_OSX
339
 - (void)setBackgroundColor:(UIColor *)backgroundColor
391
 - (void)setBackgroundColor:(UIColor *)backgroundColor
392
+#else
393
+- (void)setBackgroundColor:(RCTUIColor *)backgroundColor
394
+#endif // !TARGET_OS_OSX
340
 {
395
 {
341
   _savedBackgroundColor = backgroundColor;
396
   _savedBackgroundColor = backgroundColor;
342
   if (_webView == nil) {
397
   if (_webView == nil) {
344
   }
399
   }
345
 
400
 
346
   CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
401
   CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
347
-  self.opaque = _webView.opaque = (alpha == 1.0);
402
+  BOOL opaque = (alpha == 1.0);
403
+#if !TARGET_OS_OSX
404
+  self.opaque = _webView.opaque = opaque;
348
   _webView.scrollView.backgroundColor = backgroundColor;
405
   _webView.scrollView.backgroundColor = backgroundColor;
349
   _webView.backgroundColor = backgroundColor;
406
   _webView.backgroundColor = backgroundColor;
407
+#else
408
+  // https://stackoverflow.com/questions/40007753/macos-wkwebview-background-transparency
409
+  NSOperatingSystemVersion version = { 10, 12, 0 };
410
+  if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:version]) {
411
+    [_webView setValue:@(opaque) forKey: @"drawsBackground"];
412
+  } else {
413
+    [_webView setValue:@(!opaque) forKey: @"drawsTransparentBackground"];
414
+  }
415
+#endif // !TARGET_OS_OSX
350
 }
416
 }
351
 
417
 
352
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
418
 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
372
 - (void)userContentController:(WKUserContentController *)userContentController
438
 - (void)userContentController:(WKUserContentController *)userContentController
373
        didReceiveScriptMessage:(WKScriptMessage *)message
439
        didReceiveScriptMessage:(WKScriptMessage *)message
374
 {
440
 {
375
-  if (_onMessage != nil) {
376
-    NSMutableDictionary<NSString *, id> *event = [self baseEvent];
377
-    [event addEntriesFromDictionary: @{@"data": message.body}];
378
-    _onMessage(event);
441
+  if ([message.name isEqualToString:HistoryShimName]) {
442
+    if (_onLoadingFinish) {
443
+      NSMutableDictionary<NSString *, id> *event = [self baseEvent];
444
+      [event addEntriesFromDictionary: @{@"navigationType": message.body}];
445
+      _onLoadingFinish(event);
446
+    }
447
+  } else if ([message.name isEqualToString:MessageHandlerName]) {
448
+    if (_onMessage) {
449
+      NSMutableDictionary<NSString *, id> *event = [self baseEvent];
450
+      [event addEntriesFromDictionary: @{@"data": message.body}];
451
+      _onMessage(event);
452
+    }
379
   }
453
   }
380
 }
454
 }
381
 
455
 
401
   }
475
   }
402
 }
476
 }
403
 
477
 
478
+#if !TARGET_OS_OSX
404
 - (void)setContentInset:(UIEdgeInsets)contentInset
479
 - (void)setContentInset:(UIEdgeInsets)contentInset
405
 {
480
 {
406
   _contentInset = contentInset;
481
   _contentInset = contentInset;
415
                     withScrollView:_webView.scrollView
490
                     withScrollView:_webView.scrollView
416
                       updateOffset:YES];
491
                       updateOffset:YES];
417
 }
492
 }
493
+#endif // !TARGET_OS_OSX
418
 
494
 
419
 - (void)visitSource
495
 - (void)visitSource
420
 {
496
 {
451
     }
527
     }
452
 }
528
 }
453
 
529
 
530
+#if !TARGET_OS_OSX
454
 -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAction
531
 -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAction
455
 {
532
 {
456
     if (_webView == nil) {
533
     if (_webView == nil) {
556
     object_setClass(subview, newClass);
633
     object_setClass(subview, newClass);
557
 }
634
 }
558
 
635
 
636
+// UIScrollViewDelegate method
559
 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
637
 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
560
 {
638
 {
561
   scrollView.decelerationRate = _decelerationRate;
639
   scrollView.decelerationRate = _decelerationRate;
562
 }
640
 }
641
+#endif // !TARGET_OS_OSX
563
 
642
 
564
 - (void)setScrollEnabled:(BOOL)scrollEnabled
643
 - (void)setScrollEnabled:(BOOL)scrollEnabled
565
 {
644
 {
566
   _scrollEnabled = scrollEnabled;
645
   _scrollEnabled = scrollEnabled;
646
+#if !TARGET_OS_OSX
567
   _webView.scrollView.scrollEnabled = scrollEnabled;
647
   _webView.scrollView.scrollEnabled = scrollEnabled;
648
+#endif // !TARGET_OS_OSX
568
 }
649
 }
569
 
650
 
651
+#if !TARGET_OS_OSX
652
+// UIScrollViewDelegate method
570
 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
653
 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
571
 {
654
 {
572
   // Don't allow scrolling the scrollView.
655
   // Don't allow scrolling the scrollView.
616
     _showsVerticalScrollIndicator = showsVerticalScrollIndicator;
699
     _showsVerticalScrollIndicator = showsVerticalScrollIndicator;
617
     _webView.scrollView.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
700
     _webView.scrollView.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
618
 }
701
 }
702
+#endif // !TARGET_OS_OSX
619
 
703
 
620
 - (void)postMessage:(NSString *)message
704
 - (void)postMessage:(NSString *)message
621
 {
705
 {
633
 
717
 
634
   // Ensure webview takes the position and dimensions of RNCWebView
718
   // Ensure webview takes the position and dimensions of RNCWebView
635
   _webView.frame = self.bounds;
719
   _webView.frame = self.bounds;
720
+#if !TARGET_OS_OSX
636
   _webView.scrollView.contentInset = _contentInset;
721
   _webView.scrollView.contentInset = _contentInset;
722
+#endif // !TARGET_OS_OSX
637
 }
723
 }
638
 
724
 
639
 - (NSMutableDictionary<NSString *, id> *)baseEvent
725
 - (NSMutableDictionary<NSString *, id> *)baseEvent
695
 #pragma mark - WKNavigationDelegate methods
781
 #pragma mark - WKNavigationDelegate methods
696
 
782
 
697
 /**
783
 /**
698
-* alert
699
-*/
784
+ * alert
785
+ */
700
 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
786
 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
701
 {
787
 {
702
-    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
703
-    [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
704
-        completionHandler();
705
-    }]];
706
-    [[self topViewController] presentViewController:alert animated:YES completion:NULL];
707
-
788
+#if !TARGET_OS_OSX
789
+  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
790
+  [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
791
+    completionHandler();
792
+  }]];
793
+  [[self topViewController] presentViewController:alert animated:YES completion:NULL];
794
+#else
795
+  NSAlert *alert = [[NSAlert alloc] init];
796
+  [alert setMessageText:message];
797
+  [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(__unused NSModalResponse response){
798
+    completionHandler();
799
+  }];
800
+#endif // !TARGET_OS_OSX
708
 }
801
 }
709
 
802
 
710
 /**
803
 /**
711
-* confirm
712
-*/
804
+ * confirm
805
+ */
713
 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
806
 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
714
-    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
715
-    [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
716
-        completionHandler(YES);
717
-    }]];
718
-    [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
719
-        completionHandler(NO);
720
-    }]];
721
-    [[self topViewController] presentViewController:alert animated:YES completion:NULL];
807
+#if !TARGET_OS_OSX
808
+  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
809
+  [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
810
+    completionHandler(YES);
811
+  }]];
812
+  [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
813
+    completionHandler(NO);
814
+  }]];
815
+  [[self topViewController] presentViewController:alert animated:YES completion:NULL];
816
+#else
817
+  NSAlert *alert = [[NSAlert alloc] init];
818
+  [alert setMessageText:message];
819
+  [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")];
820
+  [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel button")];
821
+  void (^callbacksHandlers)(NSModalResponse response) = ^void(NSModalResponse response) {
822
+    completionHandler(response == NSAlertFirstButtonReturn);
823
+  };
824
+  [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:callbacksHandlers];
825
+#endif // !TARGET_OS_OSX
722
 }
826
 }
723
 
827
 
724
 /**
828
 /**
725
-* prompt
726
-*/
829
+ * prompt
830
+ */
727
 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler{
831
 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler{
728
-    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:prompt preferredStyle:UIAlertControllerStyleAlert];
729
-    [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
730
-        textField.text = defaultText;
731
-    }];
732
-    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
733
-        completionHandler([[alert.textFields lastObject] text]);
734
-    }];
735
-    [alert addAction:okAction];
736
-    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
737
-        completionHandler(nil);
738
-    }];
739
-    [alert addAction:cancelAction];
740
-    alert.preferredAction = okAction;
741
-    [[self topViewController] presentViewController:alert animated:YES completion:NULL];
832
+#if !TARGET_OS_OSX
833
+  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:prompt preferredStyle:UIAlertControllerStyleAlert];
834
+  [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
835
+    textField.text = defaultText;
836
+  }];
837
+  UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
838
+    completionHandler([[alert.textFields lastObject] text]);
839
+  }];
840
+  [alert addAction:okAction];
841
+  UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
842
+    completionHandler(nil);
843
+  }];
844
+  [alert addAction:cancelAction];
845
+  alert.preferredAction = okAction;
846
+  [[self topViewController] presentViewController:alert animated:YES completion:NULL];
847
+#else
848
+  NSAlert *alert = [[NSAlert alloc] init];
849
+  [alert setMessageText:prompt];
850
+
851
+  const NSRect RCTSingleTextFieldFrame = NSMakeRect(0.0, 0.0, 275.0, 22.0);
852
+  NSTextField *textField = [[NSTextField alloc] initWithFrame:RCTSingleTextFieldFrame];
853
+  textField.cell.scrollable = YES;
854
+  if (@available(macOS 10.11, *)) {
855
+    textField.maximumNumberOfLines = 1;
856
+  }
857
+  textField.stringValue = defaultText;
858
+  [alert setAccessoryView:textField];
859
+
860
+  [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")];
861
+  [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel button")];
862
+  [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSModalResponse response) {
863
+    if (response == NSAlertFirstButtonReturn) {
864
+      completionHandler([textField stringValue]);
865
+    } else {
866
+      completionHandler(nil);
867
+    }
868
+  }];
869
+#endif // !TARGET_OS_OSX
742
 }
870
 }
743
 
871
 
872
+#if !TARGET_OS_OSX
744
 /**
873
 /**
745
  * topViewController
874
  * topViewController
746
  */
875
  */
779
   }
908
   }
780
   return window;
909
   return window;
781
 }
910
 }
782
-
911
+#endif // !TARGET_OS_OSX
783
 
912
 
784
 /**
913
 /**
785
  * Decides whether to allow or cancel a navigation.
914
  * Decides whether to allow or cancel a navigation.
859
   decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
988
   decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
860
                     decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
989
                     decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
861
 {
990
 {
991
+  WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow;
862
   if (_onHttpError && navigationResponse.forMainFrame) {
992
   if (_onHttpError && navigationResponse.forMainFrame) {
863
     if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
993
     if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
864
       NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
994
       NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
865
       NSInteger statusCode = response.statusCode;
995
       NSInteger statusCode = response.statusCode;
866
 
996
 
867
       if (statusCode >= 400) {
997
       if (statusCode >= 400) {
868
-        NSMutableDictionary<NSString *, id> *event = [self baseEvent];
869
-        [event addEntriesFromDictionary: @{
998
+        NSMutableDictionary<NSString *, id> *httpErrorEvent = [self baseEvent];
999
+        [httpErrorEvent addEntriesFromDictionary: @{
870
           @"url": response.URL.absoluteString,
1000
           @"url": response.URL.absoluteString,
871
           @"statusCode": @(statusCode)
1001
           @"statusCode": @(statusCode)
872
         }];
1002
         }];
873
 
1003
 
874
-        _onHttpError(event);
1004
+        _onHttpError(httpErrorEvent);
1005
+      }
1006
+
1007
+      NSString *disposition = nil;
1008
+      if (@available(iOS 13, *)) {
1009
+        disposition = [response valueForHTTPHeaderField:@"Content-Disposition"];
1010
+      }
1011
+      BOOL isAttachment = disposition != nil && [disposition hasPrefix:@"attachment"];
1012
+      if (isAttachment || !navigationResponse.canShowMIMEType) {
1013
+        if (_onFileDownload) {
1014
+          policy = WKNavigationResponsePolicyCancel;
1015
+
1016
+          NSMutableDictionary<NSString *, id> *downloadEvent = [self baseEvent];
1017
+          [downloadEvent addEntriesFromDictionary: @{
1018
+            @"downloadUrl": (response.URL).absoluteString,
1019
+          }];
1020
+          _onFileDownload(downloadEvent);
1021
+        }
875
       }
1022
       }
876
     }
1023
     }
877
   }
1024
   }
878
 
1025
 
879
-  decisionHandler(WKNavigationResponsePolicyAllow);
1026
+  decisionHandler(policy);
880
 }
1027
 }
881
 
1028
 
882
 /**
1029
 /**
896
       return;
1043
       return;
897
     }
1044
     }
898
 
1045
 
899
-    if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102) {
1046
+    if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102 || [error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 101) {
900
       // Error code 102 "Frame load interrupted" is raised by the WKWebView
1047
       // Error code 102 "Frame load interrupted" is raised by the WKWebView
901
       // when the URL is from an http redirect. This is a common pattern when
1048
       // when the URL is from an http redirect. This is a common pattern when
902
       // implementing OAuth with a WebView.
1049
       // implementing OAuth with a WebView.
927
   }];
1074
   }];
928
 }
1075
 }
929
 
1076
 
1077
+-(void)forceIgnoreSilentHardwareSwitch:(BOOL)initialSetup
1078
+{
1079
+    NSString *mp3Str = @"data:audio/mp3;base64,//tAxAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAFAAAESAAzMzMzMzMzMzMzMzMzMzMzMzMzZmZmZmZmZmZmZmZmZmZmZmZmZmaZmZmZmZmZmZmZmZmZmZmZmZmZmczMzMzMzMzMzMzMzMzMzMzMzMzM//////////////////////////8AAAA5TEFNRTMuMTAwAZYAAAAAAAAAABQ4JAMGQgAAOAAABEhNIZS0AAAAAAD/+0DEAAPH3Yz0AAR8CPqyIEABp6AxjG/4x/XiInE4lfQDFwIIRE+uBgZoW4RL0OLMDFn6E5v+/u5ehf76bu7/6bu5+gAiIQGAABQIUJ0QolFghEn/9PhZQpcUTpXMjo0OGzRCZXyKxoIQzB2KhCtGobpT9TRVj/3Pmfp+f8X7Pu1B04sTnc3s0XhOlXoGVCMNo9X//9/r6a10TZEY5DsxqvO7mO5qFvpFCmKIjhpSItGsUYcRO//7QsQRgEiljQIAgLFJAbIhNBCa+JmorCbOi5q9nVd2dKnusTMQg4MFUlD6DQ4OFijwGAijRMfLbHG4nLVTjydyPlJTj8pfPflf9/5GD950A5e+jsrmNZSjSirjs1R7hnkia8vr//l/7Nb+crvr9Ok5ZJOylUKRxf/P9Zn0j2P4pJYXyKkeuy5wUYtdmOu6uobEtFqhIJViLEKIjGxchGev/L3Y0O3bwrIOszTBAZ7Ih28EUaSOZf/7QsQfg8fpjQIADN0JHbGgQBAZ8T//y//t/7d/2+f5m7MdCeo/9tdkMtGLbt1tqnabRroO1Qfvh20yEbei8nfDXP7btW7f9/uO9tbe5IvHQbLlxpf3DkAk0ojYcv///5/u3/7PTfGjPEPUvt5D6f+/3Lea4lz4tc4TnM/mFPrmalWbboeNiNyeyr+vufttZuvrVrt/WYv3T74JFo8qEDiJqJrmDTs///v99xDku2xG02jjunrICP/7QsQtA8kpkQAAgNMA/7FgQAGnobgfghgqA+uXwWQ3XFmGimSbe2X3ksY//KzK1a2k6cnNWOPJnPWUsYbKqkh8RJzrVf///P///////4vyhLKHLrCb5nIrYIUss4cthigL1lQ1wwNAc6C1pf1TIKRSkt+a//z+yLVcwlXKSqeSuCVQFLng2h4AFAFgTkH+Z/8jTX/zr//zsJV/5f//5UX/0ZNCNCCaf5lTCTRkaEdhNP//n/KUjf/7QsQ5AEhdiwAAjN7I6jGddBCO+WGTQ1mXrYatSAgaykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==";
1080
+    NSString *scr;
1081
+    if (initialSetup) {
1082
+        scr = [NSString stringWithFormat:@"var s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1083
+    } else {
1084
+        scr = [NSString stringWithFormat:@"var s=document.getElementById('wkwebviewAudio');s.src=null;s.parentNode.removeChild(s);s=null;s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1085
+    }
1086
+    [self evaluateJS: scr thenCall: nil];
1087
+}
1088
+
1089
+-(void)disableIgnoreSilentSwitch
1090
+{
1091
+    [self evaluateJS: @"document.getElementById('wkwebviewAudio').src=null;true" thenCall: nil];
1092
+}
1093
+
1094
+-(void)appDidBecomeActive
1095
+{
1096
+    if (_ignoreSilentHardwareSwitch) {
1097
+      [self forceIgnoreSilentHardwareSwitch:false];
1098
+    }
1099
+}
1100
+
1101
+-(void)appWillResignActive
1102
+{
1103
+  if (_ignoreSilentHardwareSwitch) {
1104
+    [self disableIgnoreSilentSwitch];
1105
+  }
1106
+}
1107
+
930
 /**
1108
 /**
931
  * Called when the navigation is complete.
1109
  * Called when the navigation is complete.
932
  * @see https://fburl.com/rtys6jlb
1110
  * @see https://fburl.com/rtys6jlb
933
  */
1111
  */
934
-- (void)      webView:(WKWebView *)webView
1112
+- (void)webView:(WKWebView *)webView
935
   didFinishNavigation:(WKNavigation *)navigation
1113
   didFinishNavigation:(WKNavigation *)navigation
936
 {
1114
 {
937
-  if (_injectedJavaScript) {
938
-    [self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
939
-      NSMutableDictionary *event = [self baseEvent];
940
-      event[@"jsEvaluationValue"] = jsEvaluationValue;
1115
+  if (_ignoreSilentHardwareSwitch) {
1116
+    [self forceIgnoreSilentHardwareSwitch:true];
1117
+  }
941
 
1118
 
942
-      if (self.onLoadingFinish) {
943
-        self.onLoadingFinish(event);
944
-      }
945
-    }];
946
-  } else if (_onLoadingFinish) {
1119
+  if (_onLoadingFinish) {
947
     _onLoadingFinish([self baseEvent]);
1120
     _onLoadingFinish([self baseEvent]);
948
   }
1121
   }
949
 }
1122
 }
984
   [_webView stopLoading];
1157
   [_webView stopLoading];
985
 }
1158
 }
986
 
1159
 
1160
+#if !TARGET_OS_OSX
987
 - (void)setBounces:(BOOL)bounces
1161
 - (void)setBounces:(BOOL)bounces
988
 {
1162
 {
989
   _bounces = bounces;
1163
   _bounces = bounces;
990
   _webView.scrollView.bounces = bounces;
1164
   _webView.scrollView.bounces = bounces;
991
 }
1165
 }
1166
+#endif // !TARGET_OS_OSX
1167
+
1168
+
1169
+- (void)setInjectedJavaScript:(NSString *)source {
1170
+  _injectedJavaScript = source;
1171
+
1172
+  self.atEndScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1173
+      injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
1174
+    forMainFrameOnly:_injectedJavaScriptForMainFrameOnly];
1175
+
1176
+  if(_webView != nil){
1177
+    [self resetupScripts:_webView.configuration];
1178
+  }
1179
+}
1180
+
1181
+- (void)setInjectedJavaScriptBeforeContentLoaded:(NSString *)source {
1182
+  _injectedJavaScriptBeforeContentLoaded = source;
1183
+
1184
+  self.atStartScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source
1185
+       injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1186
+    forMainFrameOnly:_injectedJavaScriptBeforeContentLoadedForMainFrameOnly];
1187
+
1188
+  if(_webView != nil){
1189
+    [self resetupScripts:_webView.configuration];
1190
+  }
1191
+}
1192
+
1193
+- (void)setInjectedJavaScriptForMainFrameOnly:(BOOL)mainFrameOnly {
1194
+  _injectedJavaScriptForMainFrameOnly = mainFrameOnly;
1195
+  [self setInjectedJavaScript:_injectedJavaScript];
1196
+}
1197
+
1198
+- (void)setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly:(BOOL)mainFrameOnly {
1199
+  _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = mainFrameOnly;
1200
+  [self setInjectedJavaScriptBeforeContentLoaded:_injectedJavaScriptBeforeContentLoaded];
1201
+}
1202
+
1203
+- (void)setMessagingEnabled:(BOOL)messagingEnabled {
1204
+  _messagingEnabled = messagingEnabled;
1205
+
1206
+  self.postMessageScript = _messagingEnabled ?
1207
+  [
1208
+   [WKUserScript alloc]
1209
+   initWithSource: [
1210
+                    NSString
1211
+                    stringWithFormat:
1212
+                    @"window.%@ = {"
1213
+                    "  postMessage: function (data) {"
1214
+                    "    window.webkit.messageHandlers.%@.postMessage(String(data));"
1215
+                    "  }"
1216
+                    "};", MessageHandlerName, MessageHandlerName
1217
+                    ]
1218
+   injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1219
+   /* TODO: For a separate (minor) PR: use logic like this (as react-native-wkwebview does) so that messaging can be used in all frames if desired.
1220
+    *       I am keeping it as YES for consistency with previous behaviour. */
1221
+   // forMainFrameOnly:_messagingEnabledForMainFrameOnly
1222
+   forMainFrameOnly:YES
1223
+   ] :
1224
+  nil;
1225
+
1226
+  if(_webView != nil){
1227
+    [self resetupScripts:_webView.configuration];
1228
+  }
1229
+}
1230
+
1231
+- (void)resetupScripts:(WKWebViewConfiguration *)wkWebViewConfig {
1232
+  [wkWebViewConfig.userContentController removeAllUserScripts];
1233
+  [wkWebViewConfig.userContentController removeScriptMessageHandlerForName:MessageHandlerName];
1234
+
1235
+  NSString *html5HistoryAPIShimSource = [NSString stringWithFormat:
1236
+    @"(function(history) {\n"
1237
+    "  function notify(type) {\n"
1238
+    "    setTimeout(function() {\n"
1239
+    "      window.webkit.messageHandlers.%@.postMessage(type)\n"
1240
+    "    }, 0)\n"
1241
+    "  }\n"
1242
+    "  function shim(f) {\n"
1243
+    "    return function pushState() {\n"
1244
+    "      notify('other')\n"
1245
+    "      return f.apply(history, arguments)\n"
1246
+    "    }\n"
1247
+    "  }\n"
1248
+    "  history.pushState = shim(history.pushState)\n"
1249
+    "  history.replaceState = shim(history.replaceState)\n"
1250
+    "  window.addEventListener('popstate', function() {\n"
1251
+    "    notify('backforward')\n"
1252
+    "  })\n"
1253
+    "})(window.history)\n", HistoryShimName
1254
+  ];
1255
+  WKUserScript *script = [[WKUserScript alloc] initWithSource:html5HistoryAPIShimSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
1256
+  [wkWebViewConfig.userContentController addUserScript:script];
1257
+
1258
+  if(_sharedCookiesEnabled) {
1259
+    // More info to sending cookies with WKWebView
1260
+    // https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
1261
+    if (@available(iOS 11.0, *)) {
1262
+      // Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies
1263
+      // See also https://forums.developer.apple.com/thread/97194
1264
+      // check if websiteDataStore has not been initialized before
1265
+      if(!_incognito && !_cacheEnabled) {
1266
+        wkWebViewConfig.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
1267
+      }
1268
+      for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
1269
+        [wkWebViewConfig.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:nil];
1270
+      }
1271
+    } else {
1272
+      NSMutableString *script = [NSMutableString string];
1273
+
1274
+      // Clear all existing cookies in a direct called function. This ensures that no
1275
+      // javascript error will break the web content javascript.
1276
+      // We keep this code here, if someone requires that Cookies are also removed within the
1277
+      // the WebView and want to extends the current sharedCookiesEnabled option with an
1278
+      // additional property.
1279
+      // Generates JS: document.cookie = "key=; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"
1280
+      // for each cookie which is already available in the WebView context.
1281
+      /*
1282
+      [script appendString:@"(function () {\n"];
1283
+      [script appendString:@"  var cookies = document.cookie.split('; ');\n"];
1284
+      [script appendString:@"  for (var i = 0; i < cookies.length; i++) {\n"];
1285
+      [script appendString:@"    if (cookies[i].indexOf('=') !== -1) {\n"];
1286
+      [script appendString:@"      document.cookie = cookies[i].split('=')[0] + '=; Expires=Thu, 01 Jan 1970 00:00:01 GMT';\n"];
1287
+      [script appendString:@"    }\n"];
1288
+      [script appendString:@"  }\n"];
1289
+      [script appendString:@"})();\n\n"];
1290
+      */
1291
+
1292
+      // Set cookies in a direct called function. This ensures that no
1293
+      // javascript error will break the web content javascript.
1294
+        // Generates JS: document.cookie = "key=value; Path=/; Expires=Thu, 01 Jan 20xx 00:00:01 GMT;"
1295
+      // for each cookie which is available in the application context.
1296
+      [script appendString:@"(function () {\n"];
1297
+      for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
1298
+        [script appendFormat:@"document.cookie = %@ + '=' + %@",
1299
+          RCTJSONStringify(cookie.name, NULL),
1300
+          RCTJSONStringify(cookie.value, NULL)];
1301
+        if (cookie.path) {
1302
+          [script appendFormat:@" + '; Path=' + %@", RCTJSONStringify(cookie.path, NULL)];
1303
+        }
1304
+        if (cookie.expiresDate) {
1305
+          [script appendFormat:@" + '; Expires=' + new Date(%f).toUTCString()",
1306
+            cookie.expiresDate.timeIntervalSince1970 * 1000
1307
+          ];
1308
+        }
1309
+        [script appendString:@";\n"];
1310
+      }
1311
+      [script appendString:@"})();\n"];
1312
+
1313
+      WKUserScript* cookieInScript = [[WKUserScript alloc] initWithSource:script
1314
+                                                            injectionTime:WKUserScriptInjectionTimeAtDocumentStart
1315
+                                                         forMainFrameOnly:YES];
1316
+      [wkWebViewConfig.userContentController addUserScript:cookieInScript];
1317
+    }
1318
+  }
1319
+
1320
+  if(_messagingEnabled){
1321
+    if (self.postMessageScript){
1322
+      [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self]
1323
+                                                                       name:MessageHandlerName];
1324
+      [wkWebViewConfig.userContentController addUserScript:self.postMessageScript];
1325
+    }
1326
+    if (self.atEndScript) {
1327
+      [wkWebViewConfig.userContentController addUserScript:self.atEndScript];
1328
+    }
1329
+  }
1330
+  // Whether or not messaging is enabled, add the startup script if it exists.
1331
+  if (self.atStartScript) {
1332
+    [wkWebViewConfig.userContentController addUserScript:self.atStartScript];
1333
+  }
1334
+}
992
 
1335
 
993
 - (NSURLRequest *)requestForSource:(id)json {
1336
 - (NSURLRequest *)requestForSource:(id)json {
994
   NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
1337
   NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
1011
 }
1354
 }
1012
 
1355
 
1013
 @end
1356
 @end
1357
+
1358
+@implementation RNCWeakScriptMessageDelegate
1359
+
1360
+- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
1361
+    self = [super init];
1362
+    if (self) {
1363
+        _scriptDelegate = scriptDelegate;
1364
+    }
1365
+    return self;
1366
+}
1367
+
1368
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
1369
+    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
1370
+}
1371
+
1372
+@end

ios/RNCWebViewManager.h → apple/RNCWebViewManager.h View File


ios/RNCWebViewManager.m → apple/RNCWebViewManager.m View File

14
 @interface RNCWebViewManager () <RNCWebViewDelegate>
14
 @interface RNCWebViewManager () <RNCWebViewDelegate>
15
 @end
15
 @end
16
 
16
 
17
-@implementation RCTConvert (UIScrollView)
18
-
19
-#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
20
-RCT_ENUM_CONVERTER(UIScrollViewContentInsetAdjustmentBehavior, (@{
21
-                                                                  @"automatic": @(UIScrollViewContentInsetAdjustmentAutomatic),
22
-                                                                  @"scrollableAxes": @(UIScrollViewContentInsetAdjustmentScrollableAxes),
23
-                                                                  @"never": @(UIScrollViewContentInsetAdjustmentNever),
24
-                                                                  @"always": @(UIScrollViewContentInsetAdjustmentAlways),
25
-                                                                  }), UIScrollViewContentInsetAdjustmentNever, integerValue)
26
-#endif
27
-
28
-@end
29
-
30
 @implementation RNCWebViewManager
17
 @implementation RNCWebViewManager
31
 {
18
 {
32
   NSConditionLock *_shouldStartLoadLock;
19
   NSConditionLock *_shouldStartLoadLock;
35
 
22
 
36
 RCT_EXPORT_MODULE()
23
 RCT_EXPORT_MODULE()
37
 
24
 
25
+#if !TARGET_OS_OSX
38
 - (UIView *)view
26
 - (UIView *)view
27
+#else
28
+- (RCTUIView *)view
29
+#endif // !TARGET_OS_OSX
39
 {
30
 {
40
   RNCWebView *webView = [RNCWebView new];
31
   RNCWebView *webView = [RNCWebView new];
41
   webView.delegate = self;
32
   webView.delegate = self;
43
 }
34
 }
44
 
35
 
45
 RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
36
 RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
37
+RCT_EXPORT_VIEW_PROPERTY(onFileDownload, RCTDirectEventBlock)
46
 RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
38
 RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
47
 RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
39
 RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
48
 RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
40
 RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
51
 RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
43
 RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
52
 RCT_EXPORT_VIEW_PROPERTY(onContentProcessDidTerminate, RCTDirectEventBlock)
44
 RCT_EXPORT_VIEW_PROPERTY(onContentProcessDidTerminate, RCTDirectEventBlock)
53
 RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
45
 RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
46
+RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoaded, NSString)
47
+RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptForMainFrameOnly, BOOL)
48
+RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoadedForMainFrameOnly, BOOL)
54
 RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)
49
 RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)
50
+RCT_EXPORT_VIEW_PROPERTY(javaScriptCanOpenWindowsAutomatically, BOOL)
51
+RCT_EXPORT_VIEW_PROPERTY(allowFileAccessFromFileURLs, BOOL)
55
 RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
52
 RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
56
 RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL)
53
 RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL)
57
 #if WEBKIT_IOS_10_APIS_AVAILABLE
54
 #if WEBKIT_IOS_10_APIS_AVAILABLE
109
     view.sharedCookiesEnabled = json == nil ? false : [RCTConvert BOOL: json];
106
     view.sharedCookiesEnabled = json == nil ? false : [RCTConvert BOOL: json];
110
 }
107
 }
111
 
108
 
109
+#if !TARGET_OS_OSX
112
 RCT_CUSTOM_VIEW_PROPERTY(decelerationRate, CGFloat, RNCWebView) {
110
 RCT_CUSTOM_VIEW_PROPERTY(decelerationRate, CGFloat, RNCWebView) {
113
   view.decelerationRate = json == nil ? UIScrollViewDecelerationRateNormal : [RCTConvert CGFloat: json];
111
   view.decelerationRate = json == nil ? UIScrollViewDecelerationRateNormal : [RCTConvert CGFloat: json];
114
 }
112
 }
113
+#endif // !TARGET_OS_OSX
115
 
114
 
116
 RCT_CUSTOM_VIEW_PROPERTY(directionalLockEnabled, BOOL, RNCWebView) {
115
 RCT_CUSTOM_VIEW_PROPERTY(directionalLockEnabled, BOOL, RNCWebView) {
117
     view.directionalLockEnabled = json == nil ? true : [RCTConvert BOOL: json];
116
     view.directionalLockEnabled = json == nil ? true : [RCTConvert BOOL: json];

+ 1
- 0
babel.config.js View File

6
         presets: ['module:metro-react-native-babel-preset'],
6
         presets: ['module:metro-react-native-babel-preset'],
7
       },
7
       },
8
     },
8
     },
9
+    presets: ['module:metro-react-native-babel-preset'],
9
   };
10
   };
10
 };
11
 };

+ 1
- 1
bin/setup View File

18
 # React Native installed?
18
 # React Native installed?
19
 if ! [ -x "$(command -v react-native)" ]; then
19
 if ! [ -x "$(command -v react-native)" ]; then
20
   echo 'Error: React Native is not installed.' >&2
20
   echo 'Error: React Native is not installed.' >&2
21
-  echo 'Go here: https://facebook.github.io/react-native/docs/getting-started.html' >&2
21
+  echo 'Go here: https://reactnative.dev/docs/getting-started.html' >&2
22
   echo 'Use the "Building Projects With Native Code" option.'
22
   echo 'Use the "Building Projects With Native Code" option.'
23
   exit 1
23
   exit 1
24
 fi
24
 fi

+ 46
- 0
docs/Contributing.md View File

8
 
8
 
9
 After you fork the repo, clone it to your machine, and make your changes, you'll want to test them in an app.
9
 After you fork the repo, clone it to your machine, and make your changes, you'll want to test them in an app.
10
 
10
 
11
+There are two methods of testing:
12
+1) Testing within a clone of react-native-webview
13
+2) Testing in a new `react-native init` project
14
+
15
+### Testing within react-native-webview
16
+
17
+#### For all platforms:
18
+```
19
+$ yarn install
20
+```
21
+
22
+#### For Android:
23
+```
24
+$ yarn start:android
25
+```
26
+
27
+The Android example app will built, the Metro Bundler will launch, and the example app will be installed and started in the Android emulator.
28
+
29
+#### For iOS:
30
+```
31
+$ cd example/ios
32
+$ pod install
33
+$ cd ../..
34
+$ yarn start:ios
35
+```
36
+
37
+The iOS example app will be built, the Metro bundler will launch, and the example app will be install and started in the Simulator.
38
+
39
+#### for macOS:
40
+```
41
+$ open example/macos/example.xcodeproj
42
+$ yarn start:macos
43
+```
44
+
45
+The Metro Bundler will now be running in the Terminal for react-native-macos.  In XCode select the `example-macos` target and Run.
46
+
47
+#### For Windows:
48
+```
49
+$ yarn start:windows
50
+$ open example/windows/WebViewWindows.sln and click run button.
51
+```
52
+
53
+The Metro Bundler will now be running in the Terminal for react-native-windows and the example app will be install and started
54
+
55
+### Testing in a new `react-native init` project
56
+
11
 In a new `react-native init` project, do this:
57
 In a new `react-native init` project, do this:
12
 
58
 
13
 ```
59
 ```

+ 14
- 14
docs/Custom-Android.md View File

1
 While the built-in web view has a lot of features, it is not possible to handle every use-case in React Native. You can, however, extend the web view with native code without forking React Native or duplicating all the existing web view code.
1
 While the built-in web view has a lot of features, it is not possible to handle every use-case in React Native. You can, however, extend the web view with native code without forking React Native or duplicating all the existing web view code.
2
 
2
 
3
-Before you do this, you should be familiar with the concepts in [native UI components](https://facebook.github.io/react-native/docs/native-components-android). You should also familiarise yourself with the [native code for web views](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java), as you will have to use this as a reference when implementing new features—although a deep understanding is not required.
3
+Before you do this, you should be familiar with the concepts in [native UI components](https://reactnative.dev/docs/native-components-android). You should also familiarise yourself with the [native code for web views](https://github.com/react-native-community/react-native-webview/blob/master/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java), as you will have to use this as a reference when implementing new features—although a deep understanding is not required.
4
 
4
 
5
 ## Native Code
5
 ## Native Code
6
 
6
 
7
 To get started, you'll need to create a subclass of `RNCWebViewManager`, `RNCWebView`, and `ReactWebViewClient`. In your view manager, you'll then need to override:
7
 To get started, you'll need to create a subclass of `RNCWebViewManager`, `RNCWebView`, and `ReactWebViewClient`. In your view manager, you'll then need to override:
8
 
8
 
9
-* `createReactWebViewInstance`
10
-* `getName`
11
-* `addEventEmitters`
9
+- `createReactWebViewInstance`
10
+- `getName`
11
+- `addEventEmitters`
12
 
12
 
13
 ```java
13
 ```java
14
 @ReactModule(name = CustomWebViewManager.REACT_CLASS)
14
 @ReactModule(name = CustomWebViewManager.REACT_CLASS)
168
 
168
 
169
 To use your custom web view, you'll need to create a class for it. Your class must:
169
 To use your custom web view, you'll need to create a class for it. Your class must:
170
 
170
 
171
-* Export all the prop types from `WebView.propTypes`
172
-* Return a `WebView` component with the prop `nativeConfig.component` set to your native component (see below)
171
+- Export all the prop types from `WebView.propTypes`
172
+- Return a `WebView` component with the prop `nativeConfig.component` set to your native component (see below)
173
 
173
 
174
 To get your native component, you must use `requireNativeComponent`: the same as for regular custom components. However, you must pass in an extra third argument, `WebView.extraNativeComponentConfig`. This third argument contains prop types that are only required for native code.
174
 To get your native component, you must use `requireNativeComponent`: the same as for regular custom components. However, you must pass in an extra third argument, `WebView.extraNativeComponentConfig`. This third argument contains prop types that are only required for native code.
175
 
175
 
176
 ```javascript
176
 ```javascript
177
-import React, {Component, PropTypes} from 'react';
178
-import {requireNativeComponent} from 'react-native';
179
-import {WebView} from 'react-native-webview';
177
+import React, { Component, PropTypes } from 'react';
178
+import { requireNativeComponent } from 'react-native';
179
+import { WebView } from 'react-native-webview';
180
 
180
 
181
 export default class CustomWebView extends Component {
181
 export default class CustomWebView extends Component {
182
   static propTypes = WebView.propTypes;
182
   static propTypes = WebView.propTypes;
183
 
183
 
184
   render() {
184
   render() {
185
     return (
185
     return (
186
-      <WebView {...this.props} nativeConfig={{component: RCTCustomWebView}} />
186
+      <WebView {...this.props} nativeConfig={{ component: RCTCustomWebView }} />
187
     );
187
     );
188
   }
188
   }
189
 }
189
 }
191
 const RCTCustomWebView = requireNativeComponent(
191
 const RCTCustomWebView = requireNativeComponent(
192
   'RCTCustomWebView',
192
   'RCTCustomWebView',
193
   CustomWebView,
193
   CustomWebView,
194
-  WebView.extraNativeComponentConfig
194
+  WebView.extraNativeComponentConfig,
195
 );
195
 );
196
 ```
196
 ```
197
 
197
 
213
     finalUrl: 'about:blank',
213
     finalUrl: 'about:blank',
214
   };
214
   };
215
 
215
 
216
-  _onNavigationCompleted = (event) => {
217
-    const {onNavigationCompleted} = this.props;
216
+  _onNavigationCompleted = event => {
217
+    const { onNavigationCompleted } = this.props;
218
     onNavigationCompleted && onNavigationCompleted(event);
218
     onNavigationCompleted && onNavigationCompleted(event);
219
   };
219
   };
220
 
220
 
249
       ...WebView.extraNativeComponentConfig.nativeOnly,
249
       ...WebView.extraNativeComponentConfig.nativeOnly,
250
       onScrollToBottom: true,
250
       onScrollToBottom: true,
251
     },
251
     },
252
-  }
252
+  },
253
 );
253
 );
254
 ```
254
 ```

+ 45
- 11
docs/Getting-Started.md View File

2
 
2
 
3
 Here's how to get started quickly with the React Native WebView.
3
 Here's how to get started quickly with the React Native WebView.
4
 
4
 
5
-#### 1. Add react-native-webview to your dependencies
5
+## 1. Add react-native-webview to your dependencies
6
 
6
 
7
 ```
7
 ```
8
 $ yarn add react-native-webview
8
 $ yarn add react-native-webview
9
 ```
9
 ```
10
- (or)
11
- 
12
- For npm use
10
+
11
+(or)
12
+
13
+For npm use
14
+
13
 ```
15
 ```
14
 $ npm install --save react-native-webview
16
 $ npm install --save react-native-webview
15
 ```
17
 ```
16
 
18
 
17
-#### 2. Link native dependencies
19
+## 2. Link native dependencies
18
 
20
 
19
 From react-native 0.60 autolinking will take care of the link step but don't forget to run `pod install`
21
 From react-native 0.60 autolinking will take care of the link step but don't forget to run `pod install`
20
 
22
 
24
 $ react-native link react-native-webview
26
 $ react-native link react-native-webview
25
 ```
27
 ```
26
 
28
 
27
-iOS:
29
+_NOTE: If you ever need to uninstall React Native WebView, run `react-native unlink react-native-webview` to unlink it._
30
+
31
+### iOS & macOS:
32
+
33
+If using CocoaPods, in the `ios/` or `macos/` directory run:
28
 
34
 
29
-If using cocoapods in the `ios/` directory run
30
 ```
35
 ```
31
 $ pod install
36
 $ pod install
32
 ```
37
 ```
33
 
38
 
39
+While you can manually link the old way using [react-native own tutorial](https://reactnative.dev/docs/linking-libraries-ios), we find it easier to use CocoaPods.
40
+If you wish to use CocoaPods and haven't set it up yet, please instead refer to [that article](https://engineering.brigad.co/demystifying-react-native-modules-linking-ae6c017a6b4a).
41
+
42
+### Android:
43
+
34
 Android - react-native-webview version <6:
44
 Android - react-native-webview version <6:
35
 This module does not require any extra step after running the link command 🎉
45
 This module does not require any extra step after running the link command 🎉
36
 
46
 
44
 
54
 
45
 For Android manual installation, please refer to [this article](https://engineering.brigad.co/demystifying-react-native-modules-linking-964399ec731b) where you can find detailed step on how to link any react-native project.
55
 For Android manual installation, please refer to [this article](https://engineering.brigad.co/demystifying-react-native-modules-linking-964399ec731b) where you can find detailed step on how to link any react-native project.
46
 
56
 
47
-For iOS, while you can manually link the old way using [react-native own tutorial](https://facebook.github.io/react-native/docs/linking-libraries-ios), we find it easier to use cocoapods.
48
-If you wish to use cocoapods and haven't set it up yet, please instead refer to [that article](https://engineering.brigad.co/demystifying-react-native-modules-linking-ae6c017a6b4a).
57
+### Windows:
49
 
58
 
50
-_NOTE: If you ever need to uninstall React Native WebView, run `react-native unlink react-native-webview` to unlink it._
59
+Autolinking is not yet supported for ReactNativeWindows. Make following additions to the given files manually:
60
+
61
+#### **windows/myapp.sln**
62
+
63
+Add the `ReactNativeWebView` project to your solution.
64
+
65
+1. Open the solution in Visual Studio 2019
66
+2. Right-click Solution icon in Solution Explorer > Add > Existing Project
67
+   Select `node_modules\react-native-webview\windows\ReactNativeWebView\ReactNativeWebView.vcxproj`
68
+
69
+#### **windows/myapp/myapp.vcxproj**
70
+
71
+Add a reference to `ReactNativeWebView` to your main application project. From Visual Studio 2019:
72
+
73
+1. Right-click main application project > Add > Reference...
74
+   Check `ReactNativeWebView` from Solution Projects.
75
+
76
+2. Modify files below to add the package providers to your main application project
77
+
78
+#### **pch.h**
79
+
80
+Add `#include "winrt/ReactNativeWebView.h"`.
81
+
82
+#### **app.cpp**
83
+
84
+Add `PackageProviders().Append(winrt::ReactNativeWebView::ReactPackageProvider());` before `InitializeComponent();`.
51
 
85
 
52
-#### 3. Import the webview into your component
86
+## 3. Import the webview into your component
53
 
87
 
54
 ```js
88
 ```js
55
 import React, { Component } from 'react';
89
 import React, { Component } from 'react';

+ 202
- 47
docs/Guide.md View File

8
 
8
 
9
 - [Basic Inline HTML](Guide.md#basic-inline-html)
9
 - [Basic Inline HTML](Guide.md#basic-inline-html)
10
 - [Basic URL Source](Guide.md#basic-url-source)
10
 - [Basic URL Source](Guide.md#basic-url-source)
11
+- [Loading local HTML files](Guide.md#loading-local-html-files)
11
 - [Controlling navigation state changes](Guide.md#controlling-navigation-state-changes)
12
 - [Controlling navigation state changes](Guide.md#controlling-navigation-state-changes)
12
 - [Add support for File Upload](Guide.md#add-support-for-file-upload)
13
 - [Add support for File Upload](Guide.md#add-support-for-file-upload)
13
 - [Multiple files upload](Guide.md#multiple-files-upload)
14
 - [Multiple files upload](Guide.md#multiple-files-upload)
14
 - [Add support for File Download](Guide.md#add-support-for-file-download)
15
 - [Add support for File Download](Guide.md#add-support-for-file-download)
15
 - [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
16
 - [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
17
+- [Working with custom headers, sessions, and cookies](Guide.md#working-with-custom-headers-sessions-and-cookies)
16
 
18
 
17
 ### Basic inline HTML
19
 ### Basic inline HTML
18
 
20
 
44
 import React, { Component } from 'react';
46
 import React, { Component } from 'react';
45
 import { WebView } from 'react-native-webview';
47
 import { WebView } from 'react-native-webview';
46
 
48
 
49
+class MyWeb extends Component {
50
+  render() {
51
+    return <WebView source={{ uri: 'https://reactnative.dev/' }} />;
52
+  }
53
+}
54
+```
55
+
56
+### Loading local HTML files
57
+
58
+Note: This is currently not working as discussed in [#428](https://github.com/react-native-community/react-native-webview/issues/428) and [#518](https://github.com/react-native-community/react-native-webview/issues/518). Possible workarounds include bundling all assets with webpack or similar, or running a [local webserver](https://github.com/futurepress/react-native-static-server).
59
+
60
+<details><summary>Show non-working method</summary>
61
+
62
+Sometimes you would have bundled an HTML file along with the app and would like to load the HTML asset into your WebView. To do this on iOS and Windows, you can just import the html file like any other asset as shown below.
63
+
64
+```js
65
+import React, { Component } from 'react';
66
+import { WebView } from 'react-native-webview';
67
+
68
+const myHtmlFile = require('./my-asset-folder/local-site.html');
69
+
70
+class MyWeb extends Component {
71
+  render() {
72
+    return <WebView source={myHtmlFile} />;
73
+  }
74
+}
75
+```
76
+
77
+However on Android, you need to place the HTML file inside your android project's asset directory. For example, if `local-site.html` is your HTML file and you'd like to load it into the webview, you should move the file to your project's android asset directory which is `your-project/android/app/src/main/assets/`. Then you can load the html file as shown in the following code block
78
+
79
+```js
80
+import React, { Component } from 'react';
81
+import { WebView } from 'react-native-webview';
82
+
47
 class MyWeb extends Component {
83
 class MyWeb extends Component {
48
   render() {
84
   render() {
49
     return (
85
     return (
50
-      <WebView source={{ uri: 'https://facebook.github.io/react-native/' }} />
86
+      <WebView source={{ uri: 'file:///android_asset/local-site.html' }} />
51
     );
87
     );
52
   }
88
   }
53
 }
89
 }
54
 ```
90
 ```
91
+</details>
55
 
92
 
56
 ### Controlling navigation state changes
93
 ### Controlling navigation state changes
57
 
94
 
68
     return (
105
     return (
69
       <WebView
106
       <WebView
70
         ref={ref => (this.webview = ref)}
107
         ref={ref => (this.webview = ref)}
71
-        source={{ uri: 'https://facebook.github.io/react-native/' }}
108
+        source={{ uri: 'https://reactnative.dev/' }}
72
         onNavigationStateChange={this.handleWebViewNavigationStateChange}
109
         onNavigationStateChange={this.handleWebViewNavigationStateChange}
73
       />
110
       />
74
     );
111
     );
105
 
142
 
106
     // redirect somewhere else
143
     // redirect somewhere else
107
     if (url.includes('google.com')) {
144
     if (url.includes('google.com')) {
108
-      const newURL = 'https://facebook.github.io/react-native/';
145
+      const newURL = 'https://reactnative.dev/';
109
       const redirectTo = 'window.location = "' + newURL + '"';
146
       const redirectTo = 'window.location = "' + newURL + '"';
110
       this.webview.injectJavaScript(redirectTo);
147
       this.webview.injectJavaScript(redirectTo);
111
     }
148
     }
113
 }
150
 }
114
 ```
151
 ```
115
 
152
 
116
-#### Intercepting hash URL changes
117
-
118
-While `onNavigationStateChange` will trigger on URL changes, it does not trigger when only the hash URL ("anchor") changes, e.g. from `https://example.com/users#list` to `https://example.com/users#help`.
119
-
120
-You can inject some JavaScript to wrap the history functions in order to intercept these hash URL changes.
121
-
122
-```jsx
123
-<WebView
124
-  source={{ uri: someURI }}
125
-  injectedJavaScript={`
126
-    (function() {
127
-      function wrap(fn) {
128
-        return function wrapper() {
129
-          var res = fn.apply(this, arguments);
130
-          window.ReactNativeWebView.postMessage('navigationStateChange');
131
-          return res;
132
-        }
133
-      }
134
-
135
-      history.pushState = wrap(history.pushState);
136
-      history.replaceState = wrap(history.replaceState);
137
-      window.addEventListener('popstate', function() {
138
-        window.ReactNativeWebView.postMessage('navigationStateChange');
139
-      });
140
-    })();
141
-
142
-    true;
143
-  `}
144
-  onMessage={({ nativeEvent: state }) => {
145
-    if (state.data === 'navigationStateChange') {
146
-      // Navigation state updated, can check state.canGoBack, etc.
147
-    }
148
-  }}
149
-/>
150
-```
151
-
152
-Thanks to [Janic Duplessis](https://github.com/react-native-community/react-native-webview/issues/24#issuecomment-483956651) for this workaround.
153
-
154
 ### Add support for File Upload
153
 ### Add support for File Upload
155
 
154
 
156
 ##### iOS
155
 ##### iOS
193
 </manifest>
192
 </manifest>
194
 ```
193
 ```
195
 
194
 
195
+###### Camera option availability in uploading for Android
196
+
197
+If the file input indicates that images or video is desired with [`accept`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept), then the WebView will attempt to provide options to the user to use their camera to take a picture or video.
198
+
199
+Normally, apps that do not have permission to use the camera can prompt the user to use an external app so that the requesting app has no need for permission. However, Android has made a special exception for this around the camera to reduce confusion for users. If an app _can_ request the camera permission because it has been declared, and the user has not granted the permission, it may not fire an intent that would use the camera (`MediaStore.ACTION_IMAGE_CAPTURE` or `MediaStore.ACTION_VIDEO_CAPTURE`). In this scenario, it is up to the developer to request camera permission before a file upload directly using the camera is necessary.
200
+
196
 ##### Check for File Upload support, with `static isFileUploadSupported()`
201
 ##### Check for File Upload support, with `static isFileUploadSupported()`
197
 
202
 
198
 File Upload using `<input type="file" />` is not supported for Android 4.4 KitKat (see [details](https://github.com/delight-im/Android-AdvancedWebView/issues/4#issuecomment-70372146)):
203
 File Upload using `<input type="file" />` is not supported for Android 4.4 KitKat (see [details](https://github.com/delight-im/Android-AdvancedWebView/issues/4#issuecomment-70372146)):
226
 
231
 
227
 ##### iOS
232
 ##### iOS
228
 
233
 
229
-For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
234
+On iOS, you are going to have to supply your own code to download files. You can supply an `onFileDownload` callback
235
+to the WebView component as a prop. If RNCWebView determines that a file download needs to take place, the URL where you can download the file
236
+will be given to `onFileDownload`. From that callback you can then download that file however you would like to do so.
230
 
237
 
231
-Save to gallery:
238
+NOTE: iOS 13+ is needed for the best possible download experience. On iOS 13 Apple added an API for accessing HTTP response headers, which
239
+is used to determine if an HTTP response should be a download. On iOS 12 or older, only MIME types that cannot be rendered by the webview will
240
+trigger calls to `onFileDownload`.
241
+
242
+Example:
243
+```javascript
244
+  onFileDownload = ({ nativeEvent }) => {
245
+    const { downloadUrl } = nativeEvent;
246
+    // --> Your download code goes here <--
247
+  }
248
+```
249
+
250
+To be able to save images to the gallery you need to specify this permission in your `ios/[project]/Info.plist` file:
232
 
251
 
233
 ```
252
 ```
234
 <key>NSPhotoLibraryAddUsageDescription</key>
253
 <key>NSPhotoLibraryAddUsageDescription</key>
237
 
256
 
238
 ##### Android
257
 ##### Android
239
 
258
 
240
-Add permission in AndroidManifest.xml:
259
+On Android, integration with the DownloadManager is built-in.
260
+Add this permisison in AndroidManifest.xml (only required if your app supports Android versions lower than 10):
241
 
261
 
242
 ```xml
262
 ```xml
243
 <manifest ...>
263
 <manifest ...>
244
   ......
264
   ......
245
 
265
 
246
-  <!-- this is required to save files on Android  -->
266
+  <!-- this is required to save files on Android versions lower than 10 -->
247
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
267
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
248
 
268
 
249
   ......
269
   ......
293
 
313
 
294
 This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds.
314
 This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds.
295
 
315
 
316
+By setting `injectedJavaScriptForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the top frame) if supported for the given platform.
317
+
296
 <img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
318
 <img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
297
 
319
 
298
 _Under the hood_
320
 _Under the hood_
299
 
321
 
300
-> On iOS, `injectedJavaScript` runs a method on WebView called `evaluateJavaScript:completionHandler:`
322
+> On iOS, ~~`injectedJavaScript` runs a method on WebView called `evaluateJavaScript:completionHandler:`~~ – this is no longer true as of version `8.2.0`. Instead, we use a `WKUserScript` with injection time `WKUserScriptInjectionTimeAtDocumentEnd`. As a consequence, `injectedJavaScript` no longer returns an evaluation value nor logs a warning to the console. In the unlikely event that your app depended upon this behaviour, please see migration steps [here](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-574919464) to retain equivalent behaviour.
323
+> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
324
+
325
+#### The `injectedJavaScriptBeforeContentLoaded` prop
326
+
327
+This is a script that runs **before** the web page loads for the first time. It only runs once, even if the page is reloaded or navigated away. This is useful if you want to inject anything into the window, localstorage, or document prior to the web code executing.
328
+
329
+```jsx
330
+import React, { Component } from 'react';
331
+import { View } from 'react-native';
332
+import { WebView } from 'react-native-webview';
333
+
334
+export default class App extends Component {
335
+  render() {
336
+    const runFirst = `
337
+      window.isNativeApp = true;
338
+      true; // note: this is required, or you'll sometimes get silent failures
339
+    `;
340
+    return (
341
+      <View style={{ flex: 1 }}>
342
+        <WebView
343
+          source={{
344
+            uri:
345
+              'https://github.com/react-native-community/react-native-webview',
346
+          }}
347
+          injectedJavaScriptBeforeContentLoaded={runFirst}
348
+        />
349
+      </View>
350
+    );
351
+  }
352
+}
353
+```
354
+
355
+This runs the JavaScript in the `runFirst` string before the page is loaded. In this case, the value of `window.isNativeApp` will be set to true before the web code executes.
356
+
357
+By setting `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false`, the JavaScript injection will occur on all frames (not just the top frame) if supported for the given platform. Howver, although support for `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false` has been implemented for iOS and macOS, [it is not clear](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-600275750) that it is actually possible to inject JS into iframes at this point in the page lifecycle, and so relying on the expected behaviour of this prop when set to `false` is not recommended.
358
+
359
+> On iOS, ~~`injectedJavaScriptBeforeContentLoaded` runs a method on WebView called `evaluateJavaScript:completionHandler:`~~ – this is no longer true as of version `8.2.0`. Instead, we use a `WKUserScript` with injection time `WKUserScriptInjectionTimeAtDocumentStart`. As a consequence, `injectedJavaScriptBeforeContentLoaded` no longer returns an evaluation value nor logs a warning to the console. In the unlikely event that your app depended upon this behaviour, please see migration steps [here](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-574919464) to retain equivalent behaviour.
301
 > On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
360
 > On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
302
 
361
 
303
 #### The `injectJavaScript` method
362
 #### The `injectJavaScript` method
346
 
405
 
347
 #### The `window.ReactNativeWebView.postMessage` method and `onMessage` prop
406
 #### The `window.ReactNativeWebView.postMessage` method and `onMessage` prop
348
 
407
 
349
-Being able to send JavaScript to the web page is great, but what about when the web page wants to communicate back to your React Native code? This where `window.ReactNativeWebView.postMessage` and the `onMessage` prop come in.
408
+Being able to send JavaScript to the web page is great, but what about when the web page wants to communicate back to your React Native code? This is where `window.ReactNativeWebView.postMessage` and the `onMessage` prop come in.
350
 
409
 
351
 You _must_ set `onMessage` or the `window.ReactNativeWebView.postMessage` method will not be injected into the web page.
410
 You _must_ set `onMessage` or the `window.ReactNativeWebView.postMessage` method will not be injected into the web page.
352
 
411
 
389
 This code will result in this alert:
448
 This code will result in this alert:
390
 
449
 
391
 <img alt="Alert showing communication from web page to React Native" width="200" src="https://user-images.githubusercontent.com/1479215/53671269-7e822300-3c32-11e9-9937-7ddc34ba8af3.png" />
450
 <img alt="Alert showing communication from web page to React Native" width="200" src="https://user-images.githubusercontent.com/1479215/53671269-7e822300-3c32-11e9-9937-7ddc34ba8af3.png" />
451
+
452
+### Working with custom headers, sessions, and cookies
453
+
454
+#### Setting Custom Headers
455
+
456
+In React Native WebView, you can set a custom header like this:
457
+
458
+```jsx
459
+<WebView
460
+  source={{
461
+    uri: 'http://example.com',
462
+    headers: {
463
+      'my-custom-header-key': 'my-custom-header-value',
464
+    },
465
+  }}
466
+/>
467
+```
468
+
469
+This will set the header on the first load, but not on subsequent page navigations.
470
+
471
+In order to work around this, you can track the current URL, intercept new page loads, and navigate to them yourself ([original credit for this technique to Chirag Shah from Big Binary](https://blog.bigbinary.com/2016/07/26/passing-request-headers-on-each-webview-request-in-react-native.html)):
472
+
473
+```jsx
474
+const CustomHeaderWebView = props => {
475
+  const { uri, onLoadStart, ...restProps } = props;
476
+  const [currentURI, setURI] = useState(props.source.uri);
477
+  const newSource = { ...props.source, uri: currentURI };
478
+
479
+  return (
480
+    <WebView
481
+      {...restProps}
482
+      source={newSource}
483
+      onShouldStartLoadWithRequest={request => {
484
+        // If we're loading the current URI, allow it to load
485
+        if (request.url === currentURI) return true;
486
+        // We're loading a new URL -- change state first
487
+        setURI(request.url);
488
+        return false;
489
+      }}
490
+    />
491
+  );
492
+};
493
+
494
+<CustomHeaderWebView
495
+  source={{
496
+    uri: 'http://example.com',
497
+    headers: {
498
+      'my-custom-header-key': 'my-custom-header-value',
499
+    },
500
+  }}
501
+/>;
502
+```
503
+
504
+#### Managing Cookies
505
+
506
+You can set cookies on the React Native side using the [@react-native-community/cookies](https://github.com/react-native-community/cookies) package.
507
+
508
+When you do, you'll likely want to enable the [sharedCookiesEnabled](Reference#sharedCookiesEnabled) prop as well.
509
+
510
+```jsx
511
+const App = () => {
512
+  return (
513
+    <WebView
514
+      source={{ uri: 'http://example.com' }}
515
+      sharedCookiesEnabled={true}
516
+    />
517
+  );
518
+};
519
+```
520
+
521
+If you'd like to send custom cookies in the WebView itself, you can do so in a custom header, like this:
522
+
523
+```jsx
524
+const App = () => {
525
+  return (
526
+    <WebView
527
+      source={{
528
+        uri: 'http://example.com',
529
+        headers: {
530
+          Cookie: 'cookie1=asdf; cookie2=dfasdfdas',
531
+        },
532
+      }}
533
+      sharedCookiesEnabled={true}
534
+    />
535
+  );
536
+};
537
+```
538
+
539
+Note that these cookies will only be sent on the first request unless you use the technique above for [setting custom headers on each page load](#Setting-Custom-Headers).
540
+
541
+### Hardware Silence Switch
542
+There are some inconsistencies in how the hardware silence switch is handled between embedded `audio` and `video` elements and between iOS and Android platforms.
543
+
544
+Audio on `iOS` will be muted when the hardware silence switch is in the on position, unless the `ignoreSilentHardwareSwitch` parameter is set to true.
545
+
546
+Video on `iOS` will always ignore the hardware silence switch.

+ 104
- 0
docs/README.portuguese.md
File diff suppressed because it is too large
View File


+ 308
- 88
docs/Reference.md View File

7
 - [`source`](Reference.md#source)
7
 - [`source`](Reference.md#source)
8
 - [`automaticallyAdjustContentInsets`](Reference.md#automaticallyadjustcontentinsets)
8
 - [`automaticallyAdjustContentInsets`](Reference.md#automaticallyadjustcontentinsets)
9
 - [`injectedJavaScript`](Reference.md#injectedjavascript)
9
 - [`injectedJavaScript`](Reference.md#injectedjavascript)
10
+- [`injectedJavaScriptBeforeContentLoaded`](Reference.md#injectedjavascriptbeforecontentloaded)
11
+- [`injectedJavaScriptForMainFrameOnly`](Reference.md#injectedjavascriptformainframeonly)
12
+- [`injectedJavaScriptBeforeContentLoadedForMainFrameOnly`](Reference.md#injectedjavascriptbeforecontentloadedformainframeonly)
10
 - [`mediaPlaybackRequiresUserAction`](Reference.md#mediaplaybackrequiresuseraction)
13
 - [`mediaPlaybackRequiresUserAction`](Reference.md#mediaplaybackrequiresuseraction)
11
 - [`nativeConfig`](Reference.md#nativeconfig)
14
 - [`nativeConfig`](Reference.md#nativeconfig)
12
 - [`onError`](Reference.md#onerror)
15
 - [`onError`](Reference.md#onerror)
25
 - [`onShouldStartLoadWithRequest`](Reference.md#onshouldstartloadwithrequest)
28
 - [`onShouldStartLoadWithRequest`](Reference.md#onshouldstartloadwithrequest)
26
 - [`startInLoadingState`](Reference.md#startinloadingstate)
29
 - [`startInLoadingState`](Reference.md#startinloadingstate)
27
 - [`style`](Reference.md#style)
30
 - [`style`](Reference.md#style)
31
+- [`containerStyle`](Reference.md#containerStyle)
28
 - [`decelerationRate`](Reference.md#decelerationrate)
32
 - [`decelerationRate`](Reference.md#decelerationrate)
29
 - [`domStorageEnabled`](Reference.md#domstorageenabled)
33
 - [`domStorageEnabled`](Reference.md#domstorageenabled)
30
 - [`javaScriptEnabled`](Reference.md#javascriptenabled)
34
 - [`javaScriptEnabled`](Reference.md#javascriptenabled)
35
+- [`javaScriptCanOpenWindowsAutomatically`](Reference.md#javascriptcanopenwindowsautomatically)
31
 - [`androidHardwareAccelerationDisabled`](Reference.md#androidHardwareAccelerationDisabled)
36
 - [`androidHardwareAccelerationDisabled`](Reference.md#androidHardwareAccelerationDisabled)
32
 - [`mixedContentMode`](Reference.md#mixedcontentmode)
37
 - [`mixedContentMode`](Reference.md#mixedcontentmode)
33
 - [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled)
38
 - [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled)
43
 - [`scrollEnabled`](Reference.md#scrollenabled)
48
 - [`scrollEnabled`](Reference.md#scrollenabled)
44
 - [`directionalLockEnabled`](Reference.md#directionalLockEnabled)
49
 - [`directionalLockEnabled`](Reference.md#directionalLockEnabled)
45
 - [`geolocationEnabled`](Reference.md#geolocationenabled)
50
 - [`geolocationEnabled`](Reference.md#geolocationenabled)
51
+- [`allowFileAccessFromFileURLs`](Reference.md#allowFileAccessFromFileURLs)
46
 - [`allowUniversalAccessFromFileURLs`](Reference.md#allowUniversalAccessFromFileURLs)
52
 - [`allowUniversalAccessFromFileURLs`](Reference.md#allowUniversalAccessFromFileURLs)
47
 - [`allowingReadAccessToURL`](Reference.md#allowingReadAccessToURL)
53
 - [`allowingReadAccessToURL`](Reference.md#allowingReadAccessToURL)
48
 - [`url`](Reference.md#url)
54
 - [`url`](Reference.md#url)
54
 - [`allowFileAccess`](Reference.md#allowFileAccess)
60
 - [`allowFileAccess`](Reference.md#allowFileAccess)
55
 - [`saveFormDataDisabled`](Reference.md#saveFormDataDisabled)
61
 - [`saveFormDataDisabled`](Reference.md#saveFormDataDisabled)
56
 - [`cacheEnabled`](Reference.md#cacheEnabled)
62
 - [`cacheEnabled`](Reference.md#cacheEnabled)
63
+- [`cacheMode`](Reference.md#cacheMode)
57
 - [`pagingEnabled`](Reference.md#pagingEnabled)
64
 - [`pagingEnabled`](Reference.md#pagingEnabled)
58
 - [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
65
 - [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
59
 - [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
66
 - [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
60
 - [`textZoom`](Reference.md#textZoom)
67
 - [`textZoom`](Reference.md#textZoom)
68
+- [`ignoreSilentHardwareSwitch`](Reference.md#ignoreSilentHardwareSwitch)
69
+- [`onFileDownload`](Reference.md#onFileDownload)
61
 - [`autoManageStatusBarEnabled`](Reference.md#autoManageStatusBarEnabled)
70
 - [`autoManageStatusBarEnabled`](Reference.md#autoManageStatusBarEnabled)
62
 
71
 
63
 ## Methods Index
72
 ## Methods Index
68
 - [`reload`](Reference.md#reload)
77
 - [`reload`](Reference.md#reload)
69
 - [`stopLoading`](Reference.md#stoploading)
78
 - [`stopLoading`](Reference.md#stoploading)
70
 - [`injectJavaScript`](Reference.md#injectjavascriptstr)
79
 - [`injectJavaScript`](Reference.md#injectjavascriptstr)
80
+- [`clearFormData`](Reference.md#clearFormData)
81
+- [`clearCache`](Reference.md#clearCache)
82
+- [`clearHistory`](Reference.md#clearHistory)
83
+- [`requestFocus`](Reference.md#requestFocus)
84
+- [`postMessage`](Reference.md#postMessage)
71
 
85
 
72
 ---
86
 ---
73
 
87
 
83
 
97
 
84
 **Load uri**
98
 **Load uri**
85
 
99
 
86
-- `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file.
100
+- `uri` (string) - The URI to load in the `WebView`. Can be a local or remote file, and can be changed with React state or props to navigate to a new page.
87
 - `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
101
 - `method` (string) - The HTTP Method to use. Defaults to GET if not specified. On Android, the only supported methods are GET and POST.
88
-- `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests.
102
+- `headers` (object) - Additional HTTP headers to send with the request. On Android, this can only be used with GET requests. See the [Guide](Guide.md#setting-custom-headers) for more information on setting custom headers.
89
 - `body` (string) - The HTTP body to send with the request. This must be a valid UTF-8 string, and will be sent exactly as specified, with no additional encoding (e.g. URL-escaping or base64) applied. On Android, this can only be used with POST requests.
103
 - `body` (string) - The HTTP body to send with the request. This must be a valid UTF-8 string, and will be sent exactly as specified, with no additional encoding (e.g. URL-escaping or base64) applied. On Android, this can only be used with POST requests.
90
 
104
 
91
 **Static HTML**
105
 **Static HTML**
113
 
127
 
114
 ### `injectedJavaScript`
128
 ### `injectedJavaScript`
115
 
129
 
116
-Set this to provide JavaScript that will be injected into the web page when the view loads. Make sure the string evaluates to a valid type (`true` works) and doesn't otherwise throw an exception.
130
+Set this to provide JavaScript that will be injected into the web page after the document finishes loading, but before other subresources finish loading.
117
 
131
 
118
-| Type   | Required |
119
-| ------ | -------- |
120
-| string | No       |
132
+Make sure the string evaluates to a valid type (`true` works) and doesn't otherwise throw an exception.
133
+
134
+On iOS, see [`WKUserScriptInjectionTimeAtDocumentEnd`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentend?language=objc)
135
+
136
+| Type   | Required | Platform |
137
+| ------ | -------- | -------- |
138
+| string | No       | iOS, Android, macOS
121
 
139
 
122
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
140
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
123
 
141
 
131
 })();`;
149
 })();`;
132
 
150
 
133
 <WebView
151
 <WebView
134
-  source={{ uri: 'https://facebook.github.io/react-native' }}
152
+  source={{ uri: 'https://reactnative.dev' }}
135
   injectedJavaScript={INJECTED_JAVASCRIPT}
153
   injectedJavaScript={INJECTED_JAVASCRIPT}
136
   onMessage={this.onMessage}
154
   onMessage={this.onMessage}
137
 />;
155
 />;
139
 
157
 
140
 ---
158
 ---
141
 
159
 
160
+### `injectedJavaScriptBeforeContentLoaded`
161
+
162
+Set this to provide JavaScript that will be injected into the web page after the document element is created, but before other subresources finish loading.
163
+
164
+Make sure the string evaluates to a valid type (`true` works) and doesn't otherwise throw an exception.
165
+
166
+On iOS, see [`WKUserScriptInjectionTimeAtDocumentStart`](https://developer.apple.com/documentation/webkit/wkuserscriptinjectiontime/wkuserscriptinjectiontimeatdocumentstart?language=objc)
167
+
168
+| Type   | Required | Platform |
169
+| ------ | -------- | -------- |
170
+| string | No       | iOS, macOS |
171
+
172
+To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
173
+
174
+Example:
175
+
176
+Post message a JSON object of `window.location` to be handled by [`onMessage`](Reference.md#onmessage). `window.ReactNativeWebView.postMessage` *will* be available at this time.
177
+
178
+```jsx
179
+const INJECTED_JAVASCRIPT = `(function() {
180
+    window.ReactNativeWebView.postMessage(JSON.stringify(window.location));
181
+})();`;
182
+
183
+<WebView
184
+  source={{ uri: 'https://reactnative.dev' }}
185
+  injectedJavaScriptBeforeContentLoaded={INJECTED_JAVASCRIPT}
186
+  onMessage={this.onMessage}
187
+/>;
188
+```
189
+
190
+---
191
+
192
+### `injectedJavaScriptForMainFrameOnly`
193
+
194
+If `true` (default), loads the `injectedJavaScript` only into the main frame.
195
+
196
+If `false`, loads it into all frames (e.g. iframes).
197
+
198
+| Type   | Required | Platform |
199
+| ------ | -------- | -------- |
200
+| bool | No       | iOS, macOS       |
201
+
202
+---
203
+
204
+### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`
205
+
206
+If `true` (default), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame.
207
+
208
+If `false`, loads it into all frames (e.g. iframes).
209
+
210
+Warning: although support for `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false` has been implemented for iOS and macOS, [it is not clear](https://github.com/react-native-community/react-native-webview/pull/1119#issuecomment-600275750) that it is actually possible to inject JS into iframes at this point in the page lifecycle, and so relying on the expected behaviour of this prop when set to `false` is not recommended.
211
+
212
+| Type   | Required | Platform |
213
+| ------ | -------- | -------- |
214
+| bool | No       | iOS, macOS       |
215
+
216
+---
217
+
142
 ### `mediaPlaybackRequiresUserAction`
218
 ### `mediaPlaybackRequiresUserAction`
143
 
219
 
144
 Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`. (Android API minimum version 17).
220
 Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`. (Android API minimum version 17).
145
 
221
 
146
 NOTE: the default `true` value might cause some videos to hang loading on iOS. Setting it to `false` could fix this issue.
222
 NOTE: the default `true` value might cause some videos to hang loading on iOS. Setting it to `false` could fix this issue.
147
 
223
 
148
-| Type | Required |
149
-| ---- | -------- |
150
-| bool | No       |
224
+| Type | Required | Platform |
225
+| ---- | -------- | -------- |
226
+| bool | No       | iOS, Android, macOS |
151
 
227
 
152
 ---
228
 ---
153
 
229
 
161
 - `props` (object)
237
 - `props` (object)
162
 - `viewManager` (object)
238
 - `viewManager` (object)
163
 
239
 
164
-| Type   | Required |
165
-| ------ | -------- |
166
-| object | No       |
240
+| Type   | Required | Platform |
241
+| ------ | -------- | -------- |
242
+| object | No       | iOS, Android, macOS |
167
 
243
 
168
 ---
244
 ---
169
 
245
 
179
 
255
 
180
 ```jsx
256
 ```jsx
181
 <WebView
257
 <WebView
182
-  source={{ uri: 'https://facebook.github.io/react-native' }}
258
+  source={{ uri: 'https://reactnative.dev' }}
183
   onError={syntheticEvent => {
259
   onError={syntheticEvent => {
184
     const { nativeEvent } = syntheticEvent;
260
     const { nativeEvent } = syntheticEvent;
185
     console.warn('WebView error: ', nativeEvent);
261
     console.warn('WebView error: ', nativeEvent);
219
 
295
 
220
 ```jsx
296
 ```jsx
221
 <WebView
297
 <WebView
222
-  source={{ uri: 'https://facebook.github.io/react-native' }}
298
+  source={{ uri: 'https://reactnative.dev' }}
223
   onLoad={syntheticEvent => {
299
   onLoad={syntheticEvent => {
224
     const { nativeEvent } = syntheticEvent;
300
     const { nativeEvent } = syntheticEvent;
225
     this.url = nativeEvent.url;
301
     this.url = nativeEvent.url;
252
 
328
 
253
 ```jsx
329
 ```jsx
254
 <WebView
330
 <WebView
255
-  source={{ uri: 'https://facebook.github.io/react-native' }}
331
+  source={{ uri: 'https://reactnative.dev' }}
256
   onLoadEnd={syntheticEvent => {
332
   onLoadEnd={syntheticEvent => {
257
     // update component to be aware of loading status
333
     // update component to be aware of loading status
258
     const { nativeEvent } = syntheticEvent;
334
     const { nativeEvent } = syntheticEvent;
286
 
362
 
287
 ```jsx
363
 ```jsx
288
 <WebView
364
 <WebView
289
-  source={{ uri: 'https://facebook.github.io/react-native/=' }}
365
+  source={{ uri: 'https://reactnative.dev/=' }}
290
   onLoadStart={syntheticEvent => {
366
   onLoadStart={syntheticEvent => {
291
     // update component to be aware of loading status
367
     // update component to be aware of loading status
292
     const { nativeEvent } = syntheticEvent;
368
     const { nativeEvent } = syntheticEvent;
312
 
388
 
313
 Function that is invoked when the `WebView` is loading.
389
 Function that is invoked when the `WebView` is loading.
314
 
390
 
315
-| Type     | Required |
316
-| -------- | -------- |
317
-| function | No       |
391
+| Type     | Required | Platform |
392
+| -------- | -------- | --------- |
393
+| function | No       | iOS, Android, macOS |
318
 
394
 
319
 Example:
395
 Example:
320
 
396
 
321
 ```jsx
397
 ```jsx
322
 <WebView
398
 <WebView
323
-  source={{ uri: 'https://facebook.github.io/react-native' }}
399
+  source={{ uri: 'https://reactnative.dev' }}
324
   onLoadProgress={({ nativeEvent }) => {
400
   onLoadProgress={({ nativeEvent }) => {
325
     this.loadingProgress = nativeEvent.progress;
401
     this.loadingProgress = nativeEvent.progress;
326
   }}
402
   }}
356
 
432
 
357
 ```jsx
433
 ```jsx
358
 <WebView
434
 <WebView
359
-  source={{ uri: 'https://facebook.github.io/react-native' }}
435
+  source={{ uri: 'https://reactnative.dev' }}
360
   onHttpError={syntheticEvent => {
436
   onHttpError={syntheticEvent => {
361
     const { nativeEvent } = syntheticEvent;
437
     const { nativeEvent } = syntheticEvent;
362
     console.warn(
438
     console.warn(
411
 
487
 
412
 ```jsx
488
 ```jsx
413
 <WebView
489
 <WebView
414
-  source={{ uri: 'https://facebook.github.io/react-native' }}
490
+  source={{ uri: 'https://reactnative.dev' }}
415
   onNavigationStateChange={navState => {
491
   onNavigationStateChange={navState => {
416
     // Keep track of going back navigation within component
492
     // Keep track of going back navigation within component
417
     this.canGoBack = navState.canGoBack;
493
     this.canGoBack = navState.canGoBack;
439
 
515
 
440
 Function that is invoked when the `WebView` content process is terminated.
516
 Function that is invoked when the `WebView` content process is terminated.
441
 
517
 
442
-| Type     | Required | Platform      |
443
-| -------- | -------- | ------------- |
444
-| function | No       | iOS WKWebView |
518
+| Type     | Required | Platform                |
519
+| -------- | -------- | ----------------------- |
520
+| function | No       | iOS and macOS WKWebView |
445
 
521
 
446
 Example:
522
 Example:
447
 
523
 
448
 ```jsx
524
 ```jsx
449
 <WebView
525
 <WebView
450
-  source={{ uri: 'https://facebook.github.io/react-native' }}
526
+  source={{ uri: 'https://reactnative.dev' }}
451
   onContentProcessDidTerminate={syntheticEvent => {
527
   onContentProcessDidTerminate={syntheticEvent => {
452
     const { nativeEvent } = syntheticEvent;
528
     const { nativeEvent } = syntheticEvent;
453
     console.warn('Content process terminated, reloading', nativeEvent);
529
     console.warn('Content process terminated, reloading', nativeEvent);
473
 
549
 
474
 List of origin strings to allow being navigated to. The strings allow wildcards and get matched against _just_ the origin (not the full URL). If the user taps to navigate to a new page but the new page is not in this whitelist, the URL will be handled by the OS. The default whitelisted origins are "http://*" and "https://*".
550
 List of origin strings to allow being navigated to. The strings allow wildcards and get matched against _just_ the origin (not the full URL). If the user taps to navigate to a new page but the new page is not in this whitelist, the URL will be handled by the OS. The default whitelisted origins are "http://*" and "https://*".
475
 
551
 
476
-| Type             | Required |
477
-| ---------------- | -------- |
478
-| array of strings | No       |
552
+| Type             | Required | Platform |
553
+| ---------------- | -------- | -------- |
554
+| array of strings | No       | iOS, Android, macOS |
479
 
555
 
480
 Example:
556
 Example:
481
 
557
 
482
 ```jsx
558
 ```jsx
483
 //only allow URIs that begin with https:// or git://
559
 //only allow URIs that begin with https:// or git://
484
 <WebView
560
 <WebView
485
-  source={{ uri: 'https://facebook.github.io/react-native' }}
561
+  source={{ uri: 'https://reactnative.dev' }}
486
   originWhitelist={['https://*', 'git://*']}
562
   originWhitelist={['https://*', 'git://*']}
487
 />
563
 />
488
 ```
564
 ```
493
 
569
 
494
 Function that returns a view to show if there's an error.
570
 Function that returns a view to show if there's an error.
495
 
571
 
496
-| Type     | Required |
497
-| -------- | -------- |
498
-| function | No       |
572
+| Type     | Required | Platform |
573
+| -------- | -------- | -------- |
574
+| function | No       | iOS, Android, macOS |
499
 
575
 
500
 Example:
576
 Example:
501
 
577
 
502
 ```jsx
578
 ```jsx
503
 <WebView
579
 <WebView
504
-  source={{ uri: 'https://facebook.github.io/react-native' }}
580
+  source={{ uri: 'https://reactnative.dev' }}
505
   renderError={errorName => <Error name={errorName} />}
581
   renderError={errorName => <Error name={errorName} />}
506
 />
582
 />
507
 ```
583
 ```
514
 
590
 
515
 Function that returns a loading indicator. The startInLoadingState prop must be set to true in order to use this prop.
591
 Function that returns a loading indicator. The startInLoadingState prop must be set to true in order to use this prop.
516
 
592
 
517
-| Type     | Required |
518
-| -------- | -------- |
519
-| function | No       |
593
+| Type     | Required | Platform |
594
+| -------- | -------- | -------- |
595
+| function | No       | iOS, Android, macOS |
520
 
596
 
521
 Example:
597
 Example:
522
 
598
 
523
 ```jsx
599
 ```jsx
524
 <WebView
600
 <WebView
525
-  source={{ uri: 'https://facebook.github.io/react-native' }}
601
+  source={{ uri: 'https://reactnative.dev' }}
526
   startInLoadingState={true}
602
   startInLoadingState={true}
527
   renderLoading={() => <Loading />}
603
   renderLoading={() => <Loading />}
528
 />
604
 />
546
 
622
 
547
 On Android, is not called on the first load.
623
 On Android, is not called on the first load.
548
 
624
 
549
-| Type     | Required |
550
-| -------- | -------- |
551
-| function | No       |
625
+| Type     | Required | Platform |
626
+| -------- | -------- | -------- |
627
+| function | No       | iOS, Android, macOS |
552
 
628
 
553
 Example:
629
 Example:
554
 
630
 
555
 ```jsx
631
 ```jsx
556
 <WebView
632
 <WebView
557
-  source={{ uri: 'https://facebook.github.io/react-native' }}
633
+  source={{ uri: 'https://reactnative.dev' }}
558
   onShouldStartLoadWithRequest={request => {
634
   onShouldStartLoadWithRequest={request => {
559
     // Only allow navigating within this website
635
     // Only allow navigating within this website
560
-    return request.url.startsWith('https://facebook.github.io/react-native');
636
+    return request.url.startsWith('https://reactnative.dev');
561
   }}
637
   }}
562
 />
638
 />
563
 ```
639
 ```
582
 
658
 
583
 Boolean value that forces the `WebView` to show the loading view on the first load. This prop must be set to `true` in order for the `renderLoading` prop to work.
659
 Boolean value that forces the `WebView` to show the loading view on the first load. This prop must be set to `true` in order for the `renderLoading` prop to work.
584
 
660
 
585
-| Type | Required |
586
-| ---- | -------- |
587
-| bool | No       |
661
+| Type | Required | Platform |
662
+| ---- | -------- | -------- |
663
+| bool | No       | iOS, Android, macOS |
588
 
664
 
589
 ---
665
 ---
590
 
666
 
600
 
676
 
601
 ```jsx
677
 ```jsx
602
 <WebView
678
 <WebView
603
-  source={{ uri: 'https://facebook.github.io/react-native' }}
679
+  source={{ uri: 'https://reactnative.dev' }}
604
   style={{ marginTop: 20 }}
680
   style={{ marginTop: 20 }}
605
 />
681
 />
606
 ```
682
 ```
607
 
683
 
608
 ---
684
 ---
609
 
685
 
686
+### `containerStyle`
687
+
688
+A style object that allow you to customize the `WebView` container style. Please note that there are default styles (example: you need to add `flex: 0` to the style if you want to use `height` property).
689
+
690
+| Type  | Required |
691
+| ----- | -------- |
692
+| style | No       |
693
+
694
+Example:
695
+
696
+```jsx
697
+<WebView
698
+  source={{ uri: 'https://reactnative.dev' }}
699
+  containerStyle={{ marginTop: 20 }}
700
+/>
701
+```
702
+
703
+---
704
+
610
 ### `decelerationRate`
705
 ### `decelerationRate`
611
 
706
 
612
 A floating-point number that determines how quickly the scroll view decelerates after the user lifts their finger. You may also use the string shortcuts `"normal"` and `"fast"` which match the underlying iOS settings for `UIScrollViewDecelerationRateNormal` and `UIScrollViewDecelerationRateFast` respectively:
707
 A floating-point number that determines how quickly the scroll view decelerates after the user lifts their finger. You may also use the string shortcuts `"normal"` and `"fast"` which match the underlying iOS settings for `UIScrollViewDecelerationRateNormal` and `UIScrollViewDecelerationRateFast` respectively:
632
 
727
 
633
 ### `javaScriptEnabled`
728
 ### `javaScriptEnabled`
634
 
729
 
635
-Boolean value to enable JavaScript in the `WebView`. Used on Android only as JavaScript is enabled by default on iOS. The default value is `true`.
730
+Boolean value to enable JavaScript in the `WebView`. The default value is `true`.
636
 
731
 
637
-| Type | Required | Platform |
638
-| ---- | -------- | -------- |
639
-| bool | No       | Android  |
732
+| Type | Required |
733
+| ---- | -------- |
734
+| bool | No       |
735
+
736
+---
737
+
738
+### `javaScriptCanOpenWindowsAutomatically`
739
+
740
+A Boolean value indicating whether JavaScript can open windows without user interaction. The default value is `false`.
741
+
742
+| Type | Required |
743
+| ---- | -------- |
744
+| bool | No       |
640
 
745
 
641
 ---
746
 ---
642
 
747
 
668
 
773
 
669
 ### `thirdPartyCookiesEnabled`
774
 ### `thirdPartyCookiesEnabled`
670
 
775
 
671
-Boolean value to enable third party cookies in the `WebView`. Used on Android Lollipop and above only as third party cookies are enabled by default on Android Kitkat and below and on iOS. The default value is `true`.
776
+Boolean value to enable third party cookies in the `WebView`. Used on Android Lollipop and above only as third party cookies are enabled by default on Android Kitkat and below and on iOS. The default value is `true`. For more on cookies, read the [Guide](Guide.md#Managing-Cookies)
672
 
777
 
673
 | Type | Required | Platform |
778
 | Type | Required | Platform |
674
 | ---- | -------- | -------- |
779
 | ---- | -------- | -------- |
680
 
785
 
681
 Sets the user-agent for the `WebView`.
786
 Sets the user-agent for the `WebView`.
682
 
787
 
683
-| Type   | Required |
684
-| ------ | -------- |
685
-| string | No       |
788
+| Type   | Required | Platform |
789
+| ------ | -------- | -------- |
790
+| string | No       | iOS, Android, macOS |
686
 
791
 
687
 ---
792
 ---
688
 
793
 
690
 
795
 
691
 Append to the existing user-agent. Setting `userAgent` will override this.
796
 Append to the existing user-agent. Setting `userAgent` will override this.
692
 
797
 
693
-| Type   | Required |
694
-| ------ | -------- |
695
-| string | No       |
798
+| Type   | Required | Platform |
799
+| ------ | -------- | -------- |
800
+| string | No       | iOS, Android, macOS |
696
 
801
 
697
 ```jsx
802
 ```jsx
698
 <WebView
803
 <WebView
699
-  source={{ uri: 'https://facebook.github.io/react-native' }}
804
+  source={{ uri: 'https://reactnative.dev' }}
700
   applicationNameForUserAgent={'DemoApp/1.1.0'}
805
   applicationNameForUserAgent={'DemoApp/1.1.0'}
701
 />
806
 />
702
 // Resulting User-Agent will look like:
807
 // Resulting User-Agent will look like:
809
 
914
 
810
 Boolean value that determines whether scrolling is enabled in the `WebView`. The default value is `true`. Setting this to `false` will prevent the webview from moving the document body when the keyboard appears over an input.
915
 Boolean value that determines whether scrolling is enabled in the `WebView`. The default value is `true`. Setting this to `false` will prevent the webview from moving the document body when the keyboard appears over an input.
811
 
916
 
812
-| Type | Required | Platform |
813
-| ---- | -------- | -------- |
814
-| bool | No       | iOS      |
917
+| Type | Required | Platform      |
918
+| ---- | -------- | ------------- |
919
+| bool | No       | iOS and macOS |
815
 
920
 
816
 ---
921
 ---
817
 
922
 
830
 
935
 
831
 Boolean value that determines whether a horizontal scroll indicator is shown in the `WebView`. The default value is `true`.
936
 Boolean value that determines whether a horizontal scroll indicator is shown in the `WebView`. The default value is `true`.
832
 
937
 
833
-| Type | Required |
834
-| ---- | -------- |
835
-| bool | No       |
938
+| Type | Required | Platform |
939
+| ---- | -------- | -------- |
940
+| bool | No       | iOS, Android, macOS |
836
 
941
 
837
 ---
942
 ---
838
 
943
 
840
 
945
 
841
 Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`. The default value is `true`.
946
 Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`. The default value is `true`.
842
 
947
 
843
-| Type | Required |
844
-| ---- | -------- |
845
-| bool | No       |
948
+| Type | Required | Platform |
949
+| ---- | -------- | -------- |
950
+| bool | No       | iOS, Android, macOS |
846
 
951
 
847
 ---
952
 ---
848
 
953
 
856
 
961
 
857
 ---
962
 ---
858
 
963
 
964
+### `allowFileAccessFromFileURLs`
965
+
966
+Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from other file scheme URLs. The default value is `false`.
967
+
968
+| Type | Required | Platform |
969
+| ---- | -------- | -------- |
970
+| bool | No       | iOS, Android, macOS |
971
+
972
+---
973
+
859
 ### `allowUniversalAccessFromFileURLs`
974
 ### `allowUniversalAccessFromFileURLs`
860
 
975
 
861
 Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from any origin. Including accessing content from other file scheme URLs. The default value is `false`.
976
 Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from any origin. Including accessing content from other file scheme URLs. The default value is `false`.
870
 
985
 
871
 A String value that indicates which URLs the WebView's file can then reference in scripts, AJAX requests, and CSS imports. This is only used in for WebViews that are loaded with a source.uri set to a `'file://'` URL. If not provided, the default is to only allow read access to the URL provided in source.uri itself.
986
 A String value that indicates which URLs the WebView's file can then reference in scripts, AJAX requests, and CSS imports. This is only used in for WebViews that are loaded with a source.uri set to a `'file://'` URL. If not provided, the default is to only allow read access to the URL provided in source.uri itself.
872
 
987
 
873
-| Type   | Required | Platform |
874
-| ------ | -------- | -------- |
875
-| string | No       | iOS      |
988
+| Type   | Required | Platform      |
989
+| ------ | -------- | ------------- |
990
+| string | No       | iOS and macOS |
876
 
991
 
877
 ---
992
 ---
878
 
993
 
920
 
1035
 
921
 If true, this will be able horizontal swipe gestures. The default value is `false`.
1036
 If true, this will be able horizontal swipe gestures. The default value is `false`.
922
 
1037
 
923
-| Type    | Required | Platform |
924
-| ------- | -------- | -------- |
925
-| boolean | No       | iOS      |
1038
+| Type    | Required | Platform      |
1039
+| ------- | -------- | ------------- |
1040
+| boolean | No       | iOS and macOS |
926
 
1041
 
927
 ---
1042
 ---
928
 
1043
 
930
 
1045
 
931
 Does not store any data within the lifetime of the WebView.
1046
 Does not store any data within the lifetime of the WebView.
932
 
1047
 
933
-| Type    | Required |
934
-| ------- | -------- |
935
-| boolean | No       |
1048
+| Type    | Required | Platform |
1049
+| ------- | -------- | -------- |
1050
+| boolean | No       | iOS, Android, macOS |
936
 
1051
 
937
 ---
1052
 ---
938
 
1053
 
960
 
1075
 
961
 Sets whether WebView should use browser caching.
1076
 Sets whether WebView should use browser caching.
962
 
1077
 
963
-| Type    | Required | Default |
964
-| ------- | -------- | ------- |
965
-| boolean | No       | true    |
1078
+| Type    | Required | Default | Platform |
1079
+| ------- | -------- | ------- | -------- |
1080
+| boolean | No       | true    | iOS, Android, macOS |
1081
+
1082
+---
1083
+
1084
+### `cacheMode`
1085
+
1086
+Overrides the way the cache is used. The way the cache is used is based on the navigation type. For a normal page load, the cache is checked and content is re-validated as needed. When navigating back, content is not revalidated, instead the content is just retrieved from the cache. This property allows the client to override this behavior.
1087
+
1088
+Possible values are:
1089
+
1090
+- `LOAD_DEFAULT` - Default cache usage mode. If the navigation type doesn't impose any specific behavior, use cached resources when they are available and not expired, otherwise load resources from the network.
1091
+- `LOAD_CACHE_ELSE_NETWORK` - Use cached resources when they are available, even if they have expired. Otherwise load resources from the network.
1092
+- `LOAD_NO_CACHE` - Don't use the cache, load from the network.
1093
+- `LOAD_CACHE_ONLY` - Don't use the network, load from the cache.
1094
+
1095
+| Type   | Required | Default      | Platform |
1096
+| ------ | -------- | ------------ | -------- |
1097
+| string | No       | LOAD_DEFAULT | Android  |
966
 
1098
 
967
 ---
1099
 ---
968
 
1100
 
980
 
1112
 
981
 A Boolean value that determines whether pressing on a link displays a preview of the destination for the link. In iOS this property 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.
1113
 A Boolean value that determines whether pressing on a link displays a preview of the destination for the link. In iOS this property 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.
982
 
1114
 
983
-| Type    | Required | Platform |
984
-| ------- | -------- | -------- |
985
-| boolean | No       | iOS      |
1115
+| Type    | Required | Platform      |
1116
+| ------- | -------- | ------------- |
1117
+| boolean | No       | iOS and macOS |
986
 
1118
 
987
 ---
1119
 ---
988
 
1120
 
989
 ### `sharedCookiesEnabled`
1121
 ### `sharedCookiesEnabled`
990
 
1122
 
991
-Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage]` should used for every load request in the WebView. The default value is `false`.
1123
+Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage]` should used for every load request in the WebView. The default value is `false`. For more on cookies, read the [Guide](Guide.md#Managing-Cookies)
992
 
1124
 
993
-| Type    | Required | Platform |
994
-| ------- | -------- | -------- |
995
-| boolean | No       | iOS      |
1125
+| Type    | Required | Platform      |
1126
+| ------- | -------- | ------------- |
1127
+| boolean | No       | iOS and macOS |
996
 
1128
 
997
 ---
1129
 ---
998
 
1130
 
1010
 
1142
 
1011
 `<WebView textZoom={100} />`
1143
 `<WebView textZoom={100} />`
1012
 
1144
 
1145
+### `ignoreSilentHardwareSwitch`
1146
+
1147
+(ios only)
1148
+
1149
+When set to true the hardware silent switch is ignored. Default: `false`
1150
+
1151
+| Type    | Required | Platform |
1152
+| ------- | -------- | -------- |
1153
+| boolean | No       | iOS      |
1154
+
1155
+### `onFileDownload`
1156
+This property is iOS-only.
1157
+
1158
+Function that is invoked when the client needs to download a file.
1159
+
1160
+iOS 13+ only: If the webview navigates to a URL that results in an HTTP
1161
+response with a Content-Disposition header 'attachment...', then
1162
+this will be called.
1163
+
1164
+iOS 8+: If the MIME type indicates that the content is not renderable by the
1165
+webview, that will also cause this to be called. On iOS versions before 13,
1166
+this is the only condition that will cause this function to be called.
1167
+
1168
+The application will need to provide its own code to actually download
1169
+the file.
1170
+
1171
+If not provided, the default is to let the webview try to render the file.
1172
+
1173
+Example:
1174
+```jsx
1175
+<WebView
1176
+  source={{ uri: 'https://reactnative.dev' }}
1177
+  onFileDownload={ ( { nativeEvent: { downloadUrl } } ) => {
1178
+    // You use downloadUrl which is a string to download files however you want.
1179
+  }}
1180
+  />
1181
+```
1182
+
1183
+| Type    | Required | Platform |
1184
+| ------- | -------- | -------- |
1185
+| function | No       | iOS      |
1186
+
1187
+
1013
 ---
1188
 ---
1014
 
1189
 
1015
 ### `autoManageStatusBarEnabled`
1190
 ### `autoManageStatusBarEnabled`
1074
 
1249
 
1075
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
1250
 To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
1076
 
1251
 
1252
+### `requestFocus()`
1253
+
1254
+```javascript
1255
+requestFocus();
1256
+```
1257
+
1258
+Request the webView to ask for focus. (People working on TV apps might want having a look at this!)
1259
+
1260
+### `postMessage(str)`
1261
+
1262
+```javascript
1263
+postMessage('message');
1264
+```
1265
+Post a message to WebView, handled by [`onMessage`](Reference.md#onmessage).
1266
+
1267
+### `clearFormData()`
1268
+
1269
+(android only)
1270
+
1271
+```javascript
1272
+clearFormData();
1273
+```
1274
+
1275
+Removes the autocomplete popup from the currently focused form field, if present. [developer.android.com reference](<https://developer.android.com/reference/android/webkit/WebView.html#clearFormData()>)
1276
+
1277
+### `clearCache(bool)`
1278
+
1279
+(android only)
1280
+
1281
+```javascript
1282
+clearCache(true);
1283
+```
1284
+
1285
+Clears the resource cache. Note that the cache is per-application, so this will clear the cache for all WebViews used. [developer.android.com reference](<https://developer.android.com/reference/android/webkit/WebView.html#clearCache(boolean)>)
1286
+
1287
+### `clearHistory()`
1288
+
1289
+(android only)
1290
+
1291
+```javascript
1292
+clearHistory();
1293
+```
1294
+
1295
+Tells this WebView to clear its internal back/forward list. [developer.android.com reference](<https://developer.android.com/reference/android/webkit/WebView.html#clearHistory()>)
1296
+
1077
 ## Other Docs
1297
 ## Other Docs
1078
 
1298
 
1079
 Also check out our [Getting Started Guide](Getting-Started.md) and [In-Depth Guide](Guide.md).
1299
 Also check out our [Getting Started Guide](Getting-Started.md) and [In-Depth Guide](Guide.md).

+ 1
- 0
example/.gitattributes View File

1
+*.pbxproj -text

+ 67
- 0
example/.gitignore View File

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
+# exclude project.xcworkspace except for xcshareddata/WorkspaceSettings.xcsettings
24
+project.xcworkspace/*
25
+**/project.xcworkspace/contents.xcworkspacedata
26
+**/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
27
+
28
+# Android/IntelliJ
29
+#
30
+build/
31
+.idea
32
+.gradle
33
+local.properties
34
+*.iml
35
+
36
+# Visual Studio Code
37
+#
38
+.vscode/
39
+
40
+# node.js
41
+#
42
+node_modules/
43
+npm-debug.log
44
+yarn-error.log
45
+
46
+# BUCK
47
+buck-out/
48
+\.buckd/
49
+*.keystore
50
+!debug.keystore
51
+
52
+# fastlane
53
+#
54
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
55
+# screenshots whenever they are needed.
56
+# For more information about the recommended setup visit:
57
+# https://docs.fastlane.tools/best-practices/source-control/
58
+
59
+*/fastlane/report.xml
60
+*/fastlane/Preview.html
61
+*/fastlane/screenshots
62
+
63
+# Bundle artifact
64
+*.jsbundle
65
+
66
+# CocoaPods
67
+/ios/Pods/

+ 6
- 0
example/.prettierrc.js View File

1
+module.exports = {
2
+  bracketSpacing: false,
3
+  jsxBracketSameLine: true,
4
+  singleQuote: true,
5
+  trailingComma: 'all',
6
+};

+ 1
- 0
example/.watchmanconfig View File

1
+{}

+ 216
- 0
example/App.tsx View File

1
+import React, {Component} from 'react';
2
+import {
3
+  StyleSheet,
4
+  SafeAreaView,
5
+  Text,
6
+  TouchableOpacity,
7
+  View,
8
+  Keyboard,
9
+  Button,
10
+  Platform,
11
+} from 'react-native';
12
+
13
+import Alerts from './examples/Alerts';
14
+import Scrolling from './examples/Scrolling';
15
+import Background from './examples/Background';
16
+import Downloads from './examples/Downloads';
17
+import Uploads from './examples/Uploads';
18
+import Injection from './examples/Injection';
19
+import LocalPageLoad from './examples/LocalPageLoad';
20
+
21
+const TESTS = {
22
+  Alerts: {
23
+    title: 'Alerts',
24
+    testId: 'alerts',
25
+    description: 'Alerts tests',
26
+    render() {
27
+      return <Alerts />;
28
+    },
29
+  },
30
+  Scrolling: {
31
+    title: 'Scrolling',
32
+    testId: 'scrolling',
33
+    description: 'Scrolling event test',
34
+    render() {
35
+      return <Scrolling />;
36
+    },
37
+  },
38
+  Background: {
39
+    title: 'Background',
40
+    testId: 'background',
41
+    description: 'Background color test',
42
+    render() {
43
+      return <Background />;
44
+    },
45
+  },
46
+  Downloads: {
47
+    title: 'Downloads',
48
+    testId: 'downloads',
49
+    description: 'File downloads test',
50
+    render() {
51
+      return <Downloads />;
52
+    },
53
+  },
54
+  Uploads: {
55
+    title: 'Uploads',
56
+    testId: 'uploads',
57
+    description: 'Upload test',
58
+    render() {
59
+      return <Uploads />;
60
+    },
61
+  },
62
+  Injection: {
63
+    title: 'Injection',
64
+    testId: 'injection',
65
+    description: 'Injection test',
66
+    render() {
67
+      return <Injection />;
68
+    },
69
+  },
70
+  PageLoad: {
71
+    title: 'LocalPageLoad',
72
+    testId: 'LocalPageLoad',
73
+    description: 'Local Page load test',
74
+    render() {
75
+      return <LocalPageLoad />;
76
+    },
77
+  },
78
+};
79
+
80
+type Props = {};
81
+type State = {restarting: boolean, currentTest: Object};
82
+
83
+export default class App extends Component<Props, State> {
84
+  state = {
85
+    restarting: false,
86
+    currentTest: TESTS.Alerts,
87
+  };
88
+
89
+  _simulateRestart = () => {
90
+    this.setState({restarting: true}, () => this.setState({restarting: false}));
91
+  };
92
+
93
+  _changeTest = testName => {
94
+    this.setState({currentTest: TESTS[testName]});
95
+  };
96
+
97
+  render() {
98
+    const {restarting, currentTest} = this.state;
99
+    return (
100
+      <SafeAreaView style={styles.container}>
101
+        <TouchableOpacity
102
+          style={styles.closeKeyboardView}
103
+          onPress={() => Keyboard.dismiss()}
104
+          testID="closeKeyboard"
105
+        />
106
+
107
+        <TouchableOpacity
108
+          testID="restart_button"
109
+          onPress={this._simulateRestart}
110
+          style={styles.restartButton}
111
+          activeOpacity={0.6}>
112
+          <Text>Simulate Restart</Text>
113
+        </TouchableOpacity>
114
+
115
+        <View style={styles.testPickerContainer}>
116
+          <Button
117
+            testID="testType_alerts"
118
+            title="Alerts"
119
+            onPress={() => this._changeTest('Alerts')}
120
+          />
121
+          <Button
122
+            testID="testType_scrolling"
123
+            title="Scrolling"
124
+            onPress={() => this._changeTest('Scrolling')}
125
+          />
126
+          <Button
127
+            testID="testType_background"
128
+            title="Background"
129
+            onPress={() => this._changeTest('Background')}
130
+          />
131
+          <Button
132
+            testID="testType_injection"
133
+            title="Injection"
134
+            onPress={() => this._changeTest('Injection')}
135
+          />
136
+          <Button
137
+            testID="testType_pageLoad"
138
+            title="LocalPageLoad"
139
+            onPress={() => this._changeTest('PageLoad')}
140
+          />
141
+          {Platform.OS == "ios" && <Button
142
+            testID="testType_downloads"
143
+            title="Downloads"
144
+            onPress={() => this._changeTest('Downloads')}
145
+          />}
146
+          {Platform.OS === 'android' && <Button
147
+            testID="testType_uploads"
148
+            title="Uploads"
149
+            onPress={() => this._changeTest('Uploads')}
150
+          />}
151
+        </View>
152
+
153
+        {restarting ? null : (
154
+          <View
155
+            testID={`example-${currentTest.testId}`}
156
+            key={currentTest.title}
157
+            style={styles.exampleContainer}>
158
+            <Text style={styles.exampleTitle}>{currentTest.title}</Text>
159
+            <Text style={styles.exampleDescription}>
160
+              {currentTest.description}
161
+            </Text>
162
+            <View style={styles.exampleInnerContainer}>
163
+              {currentTest.render()}
164
+            </View>
165
+          </View>
166
+        )}
167
+      </SafeAreaView>
168
+    );
169
+  }
170
+}
171
+
172
+const styles = StyleSheet.create({
173
+  container: {
174
+    flex: 1,
175
+    backgroundColor: '#F5FCFF',
176
+    padding: 8,
177
+  },
178
+  exampleContainer: {
179
+    padding: 16,
180
+    backgroundColor: '#FFF',
181
+    borderColor: '#EEE',
182
+    borderTopWidth: 1,
183
+    borderBottomWidth: 1,
184
+    flex: 1,
185
+  },
186
+  exampleTitle: {
187
+    fontSize: 18,
188
+  },
189
+  exampleDescription: {
190
+    color: '#333333',
191
+    marginBottom: 16,
192
+  },
193
+  exampleInnerContainer: {
194
+    borderColor: '#EEE',
195
+    borderTopWidth: 1,
196
+    paddingTop: 10,
197
+    flex: 1,
198
+  },
199
+  restartButton: {
200
+    padding: 6,
201
+    fontSize: 16,
202
+    borderRadius: 5,
203
+    backgroundColor: '#F3F3F3',
204
+    alignItems: 'center',
205
+    justifyContent: 'center',
206
+    alignSelf: 'flex-end',
207
+  },
208
+  closeKeyboardView: {
209
+    width: 5,
210
+    height: 5,
211
+  },
212
+  testPickerContainer: {
213
+    flexDirection: 'row',
214
+    flexWrap: 'wrap',
215
+  },
216
+});

+ 55
- 0
example/android/app/_BUCK View File

1
+# To learn about Buck see [Docs](https://buckbuild.com/).
2
+# To run your application with Buck:
3
+# - install Buck
4
+# - `npm start` - to start the packager
5
+# - `cd android`
6
+# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7
+# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8
+# - `buck install -r android/app` - compile, install and run application
9
+#
10
+
11
+load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12
+
13
+lib_deps = []
14
+
15
+create_aar_targets(glob(["libs/*.aar"]))
16
+
17
+create_jar_targets(glob(["libs/*.jar"]))
18
+
19
+android_library(
20
+    name = "all-libs",
21
+    exported_deps = lib_deps,
22
+)
23
+
24
+android_library(
25
+    name = "app-code",
26
+    srcs = glob([
27
+        "src/main/java/**/*.java",
28
+    ]),
29
+    deps = [
30
+        ":all-libs",
31
+        ":build_config",
32
+        ":res",
33
+    ],
34
+)
35
+
36
+android_build_config(
37
+    name = "build_config",
38
+    package = "com.example",
39
+)
40
+
41
+android_resource(
42
+    name = "res",
43
+    package = "com.example",
44
+    res = "src/main/res",
45
+)
46
+
47
+android_binary(
48
+    name = "app",
49
+    keystore = "//android/keystores:debug",
50
+    manifest = "src/main/AndroidManifest.xml",
51
+    package_type = "debug",
52
+    deps = [
53
+        ":app-code",
54
+    ],
55
+)

+ 204
- 0
example/android/app/build.gradle View File

1
+apply plugin: "com.android.application"
2
+
3
+import com.android.build.OutputFile
4
+
5
+/**
6
+ * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7
+ * and bundleReleaseJsAndAssets).
8
+ * These basically call `react-native bundle` with the correct arguments during the Android build
9
+ * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10
+ * bundle directly from the development server. Below you can see all the possible configurations
11
+ * and their defaults. If you decide to add a configuration block, make sure to add it before the
12
+ * `apply from: "../../node_modules/react-native/react.gradle"` line.
13
+ *
14
+ * project.ext.react = [
15
+ *   // the name of the generated asset file containing your JS bundle
16
+ *   bundleAssetName: "index.android.bundle",
17
+ *
18
+ *   // the entry file for bundle generation
19
+ *   entryFile: "index.android.js",
20
+ *
21
+ *   // https://reactnative.dev/docs/performance#enable-the-ram-format
22
+ *   bundleCommand: "ram-bundle",
23
+ *
24
+ *   // whether to bundle JS and assets in debug mode
25
+ *   bundleInDebug: false,
26
+ *
27
+ *   // whether to bundle JS and assets in release mode
28
+ *   bundleInRelease: true,
29
+ *
30
+ *   // whether to bundle JS and assets in another build variant (if configured).
31
+ *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
32
+ *   // The configuration property can be in the following formats
33
+ *   //         'bundleIn${productFlavor}${buildType}'
34
+ *   //         'bundleIn${buildType}'
35
+ *   // bundleInFreeDebug: true,
36
+ *   // bundleInPaidRelease: true,
37
+ *   // bundleInBeta: true,
38
+ *
39
+ *   // whether to disable dev mode in custom build variants (by default only disabled in release)
40
+ *   // for example: to disable dev mode in the staging build type (if configured)
41
+ *   devDisabledInStaging: true,
42
+ *   // The configuration property can be in the following formats
43
+ *   //         'devDisabledIn${productFlavor}${buildType}'
44
+ *   //         'devDisabledIn${buildType}'
45
+ *
46
+ *   // the root of your project, i.e. where "package.json" lives
47
+ *   root: "../../",
48
+ *
49
+ *   // where to put the JS bundle asset in debug mode
50
+ *   jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
51
+ *
52
+ *   // where to put the JS bundle asset in release mode
53
+ *   jsBundleDirRelease: "$buildDir/intermediates/assets/release",
54
+ *
55
+ *   // where to put drawable resources / React Native assets, e.g. the ones you use via
56
+ *   // require('./image.png')), in debug mode
57
+ *   resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
58
+ *
59
+ *   // where to put drawable resources / React Native assets, e.g. the ones you use via
60
+ *   // require('./image.png')), in release mode
61
+ *   resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
62
+ *
63
+ *   // by default the gradle tasks are skipped if none of the JS files or assets change; this means
64
+ *   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
65
+ *   // date; if you have any other folders that you want to ignore for performance reasons (gradle
66
+ *   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
67
+ *   // for example, you might want to remove it from here.
68
+ *   inputExcludes: ["android/**", "ios/**"],
69
+ *
70
+ *   // override which node gets called and with what additional arguments
71
+ *   nodeExecutableAndArgs: ["node"],
72
+ *
73
+ *   // supply additional arguments to the packager
74
+ *   extraPackagerArgs: []
75
+ * ]
76
+ */
77
+
78
+project.ext.react = [
79
+    cliPath: "../../../node_modules/react-native/local-cli/cli.js",
80
+    entryFile: "./example/index.js",
81
+    root: "../../../",
82
+    enableHermes: false,  // clean and rebuild if changing
83
+]
84
+
85
+apply from: "../../../node_modules/react-native/react.gradle"
86
+
87
+/**
88
+ * Set this to true to create two separate APKs instead of one:
89
+ *   - An APK that only works on ARM devices
90
+ *   - An APK that only works on x86 devices
91
+ * The advantage is the size of the APK is reduced by about 4MB.
92
+ * Upload all the APKs to the Play Store and people will download
93
+ * the correct one based on the CPU architecture of their device.
94
+ */
95
+def enableSeparateBuildPerCPUArchitecture = false
96
+
97
+/**
98
+ * Run Proguard to shrink the Java bytecode in release builds.
99
+ */
100
+def enableProguardInReleaseBuilds = false
101
+
102
+/**
103
+ * The preferred build flavor of JavaScriptCore.
104
+ *
105
+ * For example, to use the international variant, you can use:
106
+ * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
107
+ *
108
+ * The international variant includes ICU i18n library and necessary data
109
+ * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
110
+ * give correct results when using with locales other than en-US.  Note that
111
+ * this variant is about 6MiB larger per architecture than default.
112
+ */
113
+def jscFlavor = 'org.webkit:android-jsc:+'
114
+
115
+/**
116
+ * Whether to enable the Hermes VM.
117
+ *
118
+ * This should be set on project.ext.react and mirrored here.  If it is not set
119
+ * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
120
+ * and the benefits of using Hermes will therefore be sharply reduced.
121
+ */
122
+def enableHermes = project.ext.react.get("enableHermes", false);
123
+
124
+android {
125
+    compileSdkVersion rootProject.ext.compileSdkVersion
126
+
127
+    compileOptions {
128
+        sourceCompatibility JavaVersion.VERSION_1_8
129
+        targetCompatibility JavaVersion.VERSION_1_8
130
+    }
131
+
132
+    defaultConfig {
133
+        applicationId "com.example"
134
+        minSdkVersion rootProject.ext.minSdkVersion
135
+        targetSdkVersion rootProject.ext.targetSdkVersion
136
+        versionCode 1
137
+        versionName "1.0"
138
+    }
139
+    splits {
140
+        abi {
141
+            reset()
142
+            enable enableSeparateBuildPerCPUArchitecture
143
+            universalApk false  // If true, also generate a universal APK
144
+            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
145
+        }
146
+    }
147
+    signingConfigs {
148
+        debug {
149
+            storeFile file('debug.keystore')
150
+            storePassword 'android'
151
+            keyAlias 'androiddebugkey'
152
+            keyPassword 'android'
153
+        }
154
+    }
155
+    buildTypes {
156
+        debug {
157
+            signingConfig signingConfigs.debug
158
+        }
159
+        release {
160
+            // Caution! In production, you need to generate your own keystore file.
161
+            // see https://reactnative.dev/docs/signed-apk-android.
162
+            signingConfig signingConfigs.debug
163
+            minifyEnabled enableProguardInReleaseBuilds
164
+            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
165
+        }
166
+    }
167
+    // applicationVariants are e.g. debug, release
168
+    applicationVariants.all { variant ->
169
+        variant.outputs.each { output ->
170
+            // For each separate APK per architecture, set a unique version code as described here:
171
+            // https://developer.android.com/studio/build/configure-apk-splits.html
172
+            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
173
+            def abi = output.getFilter(OutputFile.ABI)
174
+            if (abi != null) {  // null for the universal-debug, universal-release variants
175
+                output.versionCodeOverride =
176
+                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
177
+            }
178
+
179
+        }
180
+    }
181
+}
182
+
183
+dependencies {
184
+    implementation project(':rnWebView')
185
+    implementation fileTree(dir: "libs", include: ["*.jar"])
186
+    implementation "com.facebook.react:react-native:+"  // From node_modules
187
+
188
+    if (enableHermes) {
189
+        def hermesPath = "../../../node_modules/hermes-engine/android/";
190
+        debugImplementation files(hermesPath + "hermes-debug.aar")
191
+        releaseImplementation files(hermesPath + "hermes-release.aar")
192
+    } else {
193
+        implementation jscFlavor
194
+    }
195
+}
196
+
197
+// Run this once to be able to run the application with BUCK
198
+// puts all compile dependencies into folder libs for BUCK to use
199
+task copyDownloadableDepsToLibs(type: Copy) {
200
+    from configurations.compile
201
+    into 'libs'
202
+}
203
+
204
+apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

+ 19
- 0
example/android/app/build_defs.bzl View File

1
+"""Helper definitions to glob .aar and .jar targets"""
2
+
3
+def create_aar_targets(aarfiles):
4
+    for aarfile in aarfiles:
5
+        name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6
+        lib_deps.append(":" + name)
7
+        android_prebuilt_aar(
8
+            name = name,
9
+            aar = aarfile,
10
+        )
11
+
12
+def create_jar_targets(jarfiles):
13
+    for jarfile in jarfiles:
14
+        name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15
+        lib_deps.append(":" + name)
16
+        prebuilt_jar(
17
+            name = name,
18
+            binary_jar = jarfile,
19
+        )

BIN
example/android/app/debug.keystore View File


+ 10
- 0
example/android/app/proguard-rules.pro View File

1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4
+# You can edit the include path and order by changing the proguardFiles
5
+# directive in build.gradle.
6
+#
7
+# For more details, see
8
+#   http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+# Add any project specific keep options here:

+ 8
- 0
example/android/app/src/debug/AndroidManifest.xml View File

1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:tools="http://schemas.android.com/tools">
4
+
5
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
6
+
7
+    <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
8
+</manifest>

+ 27
- 0
example/android/app/src/main/AndroidManifest.xml View File

1
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+  package="com.example">
3
+
4
+    <uses-permission android:name="android.permission.INTERNET" />
5
+    <uses-permission android:name="android.permission.CAMERA" />
6
+
7
+    <application
8
+      android:name=".MainApplication"
9
+      android:label="@string/app_name"
10
+      android:icon="@mipmap/ic_launcher"
11
+      android:roundIcon="@mipmap/ic_launcher_round"
12
+      android:allowBackup="false"
13
+      android:theme="@style/AppTheme">
14
+      <activity
15
+        android:name=".MainActivity"
16
+        android:label="@string/app_name"
17
+        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
18
+        android:windowSoftInputMode="adjustResize">
19
+        <intent-filter>
20
+            <action android:name="android.intent.action.MAIN" />
21
+            <category android:name="android.intent.category.LAUNCHER" />
22
+        </intent-filter>
23
+      </activity>
24
+      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
25
+    </application>
26
+
27
+</manifest>

+ 15
- 0
example/android/app/src/main/java/com/example/MainActivity.java View File

1
+package com.example;
2
+
3
+import com.facebook.react.ReactActivity;
4
+
5
+public class MainActivity extends ReactActivity {
6
+
7
+  /**
8
+   * Returns the name of the main component registered from JavaScript. This is used to schedule
9
+   * rendering of the component.
10
+   */
11
+  @Override
12
+  protected String getMainComponentName() {
13
+    return "example";
14
+  }
15
+}

+ 76
- 0
example/android/app/src/main/java/com/example/MainApplication.java View File

1
+package com.example;
2
+
3
+import android.app.Application;
4
+import android.content.Context;
5
+import com.facebook.react.PackageList;
6
+import com.facebook.react.ReactApplication;
7
+import com.facebook.react.ReactNativeHost;
8
+import com.facebook.react.ReactPackage;
9
+import com.facebook.soloader.SoLoader;
10
+import com.reactnativecommunity.webview.RNCWebViewPackage;
11
+import java.lang.reflect.InvocationTargetException;
12
+import java.util.List;
13
+
14
+public class MainApplication extends Application implements ReactApplication {
15
+
16
+  private final ReactNativeHost mReactNativeHost =
17
+      new ReactNativeHost(this) {
18
+        @Override
19
+        public boolean getUseDeveloperSupport() {
20
+          return BuildConfig.DEBUG;
21
+        }
22
+
23
+        @Override
24
+        protected List<ReactPackage> getPackages() {
25
+          @SuppressWarnings("UnnecessaryLocalVariable")
26
+          List<ReactPackage> packages = new PackageList(this).getPackages();
27
+          // Packages that cannot be autolinked yet can be added manually here, for example:
28
+          // packages.add(new MyReactNativePackage());
29
+          packages.add(new RNCWebViewPackage());
30
+          return packages;
31
+        }
32
+
33
+        @Override
34
+        protected String getJSMainModuleName() {
35
+          return "example/index";
36
+        }
37
+      };
38
+
39
+  @Override
40
+  public ReactNativeHost getReactNativeHost() {
41
+    return mReactNativeHost;
42
+  }
43
+
44
+  @Override
45
+  public void onCreate() {
46
+    super.onCreate();
47
+    SoLoader.init(this, /* native exopackage */ false);
48
+    initializeFlipper(this); // Remove this line if you don't want Flipper enabled
49
+  }
50
+
51
+  /**
52
+   * Loads Flipper in React Native templates.
53
+   *
54
+   * @param context
55
+   */
56
+  private static void initializeFlipper(Context context) {
57
+    if (BuildConfig.DEBUG) {
58
+      try {
59
+        /*
60
+         We use reflection here to pick up the class that initializes Flipper,
61
+        since Flipper library is not available in release mode
62
+        */
63
+        Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
64
+        aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
65
+      } catch (ClassNotFoundException e) {
66
+        e.printStackTrace();
67
+      } catch (NoSuchMethodException e) {
68
+        e.printStackTrace();
69
+      } catch (IllegalAccessException e) {
70
+        e.printStackTrace();
71
+      } catch (InvocationTargetException e) {
72
+        e.printStackTrace();
73
+      }
74
+    }
75
+  }
76
+}

BIN
example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png View File


BIN
example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png View File


BIN
example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png View File


BIN
example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png View File


BIN
example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png View File


BIN
example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png View File


BIN
example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png View File


BIN
example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png View File


BIN
example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png View File


BIN
example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png View File


+ 3
- 0
example/android/app/src/main/res/values/strings.xml View File

1
+<resources>
2
+    <string name="app_name">example</string>
3
+</resources>

+ 9
- 0
example/android/app/src/main/res/values/styles.xml View File

1
+<resources>
2
+
3
+    <!-- Base application theme. -->
4
+    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
5
+        <!-- Customize your theme here. -->
6
+        <item name="android:textColor">#000000</item>
7
+    </style>
8
+
9
+</resources>

+ 38
- 0
example/android/build.gradle View File

1
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
2
+
3
+buildscript {
4
+    ext {
5
+        buildToolsVersion = "29.0.3"
6
+        minSdkVersion = 16
7
+        compileSdkVersion = 29
8
+        targetSdkVersion = 28
9
+    }
10
+    repositories {
11
+        google()
12
+        jcenter()
13
+    }
14
+    dependencies {
15
+        classpath("com.android.tools.build:gradle:3.5.2")
16
+
17
+        // NOTE: Do not place your application dependencies here; they belong
18
+        // in the individual module build.gradle files
19
+    }
20
+}
21
+
22
+allprojects {
23
+    repositories {
24
+        mavenLocal()
25
+        maven {
26
+            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
27
+            url("$rootDir/../../node_modules/react-native/android")
28
+        }
29
+        maven {
30
+            // Android JSC is installed from npm
31
+            url("$rootDir/../../node_modules/jsc-android/dist")
32
+        }
33
+
34
+        google()
35
+        jcenter()
36
+        maven { url 'https://www.jitpack.io' }
37
+    }
38
+}

+ 21
- 0
example/android/gradle.properties View File

1
+# Project-wide Gradle settings.
2
+
3
+# IDE (e.g. Android Studio) users:
4
+# Gradle settings configured through the IDE *will override*
5
+# any settings specified in this file.
6
+
7
+# For more details on how to configure your build environment visit
8
+# http://www.gradle.org/docs/current/userguide/build_environment.html
9
+
10
+# Specifies the JVM arguments used for the daemon process.
11
+# The setting is particularly useful for tweaking memory settings.
12
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
13
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14
+
15
+# When configured, Gradle will run in incubating parallel mode.
16
+# This option should only be used with decoupled projects. More details, visit
17
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18
+# org.gradle.parallel=true
19
+
20
+android.useAndroidX=true
21
+android.enableJetifier=true

BIN
example/android/gradle/wrapper/gradle-wrapper.jar View File


+ 5
- 0
example/android/gradle/wrapper/gradle-wrapper.properties View File

1
+distributionBase=GRADLE_USER_HOME
2
+distributionPath=wrapper/dists
3
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
4
+zipStoreBase=GRADLE_USER_HOME
5
+zipStorePath=wrapper/dists

+ 188
- 0
example/android/gradlew View File

1
+#!/usr/bin/env sh
2
+
3
+#
4
+# Copyright 2015 the original author or authors.
5
+#
6
+# Licensed under the Apache License, Version 2.0 (the "License");
7
+# you may not use this file except in compliance with the License.
8
+# You may obtain a copy of the License at
9
+#
10
+#      https://www.apache.org/licenses/LICENSE-2.0
11
+#
12
+# Unless required by applicable law or agreed to in writing, software
13
+# distributed under the License is distributed on an "AS IS" BASIS,
14
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+# See the License for the specific language governing permissions and
16
+# limitations under the License.
17
+#
18
+
19
+##############################################################################
20
+##
21
+##  Gradle start up script for UN*X
22
+##
23
+##############################################################################
24
+
25
+# Attempt to set APP_HOME
26
+# Resolve links: $0 may be a link
27
+PRG="$0"
28
+# Need this for relative symlinks.
29
+while [ -h "$PRG" ] ; do
30
+    ls=`ls -ld "$PRG"`
31
+    link=`expr "$ls" : '.*-> \(.*\)$'`
32
+    if expr "$link" : '/.*' > /dev/null; then
33
+        PRG="$link"
34
+    else
35
+        PRG=`dirname "$PRG"`"/$link"
36
+    fi
37
+done
38
+SAVED="`pwd`"
39
+cd "`dirname \"$PRG\"`/" >/dev/null
40
+APP_HOME="`pwd -P`"
41
+cd "$SAVED" >/dev/null
42
+
43
+APP_NAME="Gradle"
44
+APP_BASE_NAME=`basename "$0"`
45
+
46
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48
+
49
+# Use the maximum available, or set MAX_FD != -1 to use that value.
50
+MAX_FD="maximum"
51
+
52
+warn () {
53
+    echo "$*"
54
+}
55
+
56
+die () {
57
+    echo
58
+    echo "$*"
59
+    echo
60
+    exit 1
61
+}
62
+
63
+# OS specific support (must be 'true' or 'false').
64
+cygwin=false
65
+msys=false
66
+darwin=false
67
+nonstop=false
68
+case "`uname`" in
69
+  CYGWIN* )
70
+    cygwin=true
71
+    ;;
72
+  Darwin* )
73
+    darwin=true
74
+    ;;
75
+  MINGW* )
76
+    msys=true
77
+    ;;
78
+  NONSTOP* )
79
+    nonstop=true
80
+    ;;
81
+esac
82
+
83
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84
+
85
+# Determine the Java command to use to start the JVM.
86
+if [ -n "$JAVA_HOME" ] ; then
87
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88
+        # IBM's JDK on AIX uses strange locations for the executables
89
+        JAVACMD="$JAVA_HOME/jre/sh/java"
90
+    else
91
+        JAVACMD="$JAVA_HOME/bin/java"
92
+    fi
93
+    if [ ! -x "$JAVACMD" ] ; then
94
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95
+
96
+Please set the JAVA_HOME variable in your environment to match the
97
+location of your Java installation."
98
+    fi
99
+else
100
+    JAVACMD="java"
101
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102
+
103
+Please set the JAVA_HOME variable in your environment to match the
104
+location of your Java installation."
105
+fi
106
+
107
+# Increase the maximum file descriptors if we can.
108
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109
+    MAX_FD_LIMIT=`ulimit -H -n`
110
+    if [ $? -eq 0 ] ; then
111
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112
+            MAX_FD="$MAX_FD_LIMIT"
113
+        fi
114
+        ulimit -n $MAX_FD
115
+        if [ $? -ne 0 ] ; then
116
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
117
+        fi
118
+    else
119
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120
+    fi
121
+fi
122
+
123
+# For Darwin, add options to specify how the application appears in the dock
124
+if $darwin; then
125
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126
+fi
127
+
128
+# For Cygwin, switch paths to Windows format before running java
129
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132
+    JAVACMD=`cygpath --unix "$JAVACMD"`
133
+
134
+    # We build the pattern for arguments to be converted via cygpath
135
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136
+    SEP=""
137
+    for dir in $ROOTDIRSRAW ; do
138
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
139
+        SEP="|"
140
+    done
141
+    OURCYGPATTERN="(^($ROOTDIRS))"
142
+    # Add a user-defined pattern to the cygpath arguments
143
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145
+    fi
146
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
147
+    i=0
148
+    for arg in "$@" ; do
149
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
151
+
152
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
153
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154
+        else
155
+            eval `echo args$i`="\"$arg\""
156
+        fi
157
+        i=$((i+1))
158
+    done
159
+    case $i in
160
+        (0) set -- ;;
161
+        (1) set -- "$args0" ;;
162
+        (2) set -- "$args0" "$args1" ;;
163
+        (3) set -- "$args0" "$args1" "$args2" ;;
164
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170
+    esac
171
+fi
172
+
173
+# Escape application args
174
+save () {
175
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176
+    echo " "
177
+}
178
+APP_ARGS=$(save "$@")
179
+
180
+# Collect all arguments for the java command, following the shell quoting and substitution rules
181
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182
+
183
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
184
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
185
+  cd "$(dirname "$0")"
186
+fi
187
+
188
+exec "$JAVACMD" "$@"

+ 100
- 0
example/android/gradlew.bat View File

1
+@rem
2
+@rem Copyright 2015 the original author or authors.
3
+@rem
4
+@rem Licensed under the Apache License, Version 2.0 (the "License");
5
+@rem you may not use this file except in compliance with the License.
6
+@rem You may obtain a copy of the License at
7
+@rem
8
+@rem      http://www.apache.org/licenses/LICENSE-2.0
9
+@rem
10
+@rem Unless required by applicable law or agreed to in writing, software
11
+@rem distributed under the License is distributed on an "AS IS" BASIS,
12
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+@rem See the License for the specific language governing permissions and
14
+@rem limitations under the License.
15
+@rem
16
+
17
+@if "%DEBUG%" == "" @echo off
18
+@rem ##########################################################################
19
+@rem
20
+@rem  Gradle startup script for Windows
21
+@rem
22
+@rem ##########################################################################
23
+
24
+@rem Set local scope for the variables with windows NT shell
25
+if "%OS%"=="Windows_NT" setlocal
26
+
27
+set DIRNAME=%~dp0
28
+if "%DIRNAME%" == "" set DIRNAME=.
29
+set APP_BASE_NAME=%~n0
30
+set APP_HOME=%DIRNAME%
31
+
32
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34
+
35
+@rem Find java.exe
36
+if defined JAVA_HOME goto findJavaFromJavaHome
37
+
38
+set JAVA_EXE=java.exe
39
+%JAVA_EXE% -version >NUL 2>&1
40
+if "%ERRORLEVEL%" == "0" goto init
41
+
42
+echo.
43
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44
+echo.
45
+echo Please set the JAVA_HOME variable in your environment to match the
46
+echo location of your Java installation.
47
+
48
+goto fail
49
+
50
+:findJavaFromJavaHome
51
+set JAVA_HOME=%JAVA_HOME:"=%
52
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53
+
54
+if exist "%JAVA_EXE%" goto init
55
+
56
+echo.
57
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58
+echo.
59
+echo Please set the JAVA_HOME variable in your environment to match the
60
+echo location of your Java installation.
61
+
62
+goto fail
63
+
64
+:init
65
+@rem Get command-line arguments, handling Windows variants
66
+
67
+if not "%OS%" == "Windows_NT" goto win9xME_args
68
+
69
+:win9xME_args
70
+@rem Slurp the command line arguments.
71
+set CMD_LINE_ARGS=
72
+set _SKIP=2
73
+
74
+:win9xME_args_slurp
75
+if "x%~1" == "x" goto execute
76
+
77
+set CMD_LINE_ARGS=%*
78
+
79
+:execute
80
+@rem Setup the command line
81
+
82
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83
+
84
+@rem Execute Gradle
85
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86
+
87
+:end
88
+@rem End local scope for the variables with windows NT shell
89
+if "%ERRORLEVEL%"=="0" goto mainEnd
90
+
91
+:fail
92
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93
+rem the _cmd.exe /c_ return code!
94
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95
+exit /b 1
96
+
97
+:mainEnd
98
+if "%OS%"=="Windows_NT" endlocal
99
+
100
+:omega

+ 5
- 0
example/android/settings.gradle View File

1
+rootProject.name = 'example'
2
+apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3
+include ':app'
4
+include ':rnWebView'
5
+project(':rnWebView').projectDir = new File(rootProject.projectDir, '../../android')

+ 4
- 0
example/app.json View File

1
+{
2
+  "name": "example",
3
+  "displayName": "example"
4
+}

+ 9
- 0
example/assets/test.html View File

1
+<!doctype html>
2
+<html>
3
+    <head>
4
+        <title>Test</title>
5
+    </head>
6
+    <body>
7
+        <h2>Local page test</h2>
8
+    </body>
9
+</html>

+ 3
- 0
example/babel.config.js View File

1
+module.exports = {
2
+  presets: ['module:metro-react-native-babel-preset'],
3
+};

+ 72
- 0
example/examples/Alerts.tsx View File

1
+import React, {Component} from 'react';
2
+import {Text, View} from 'react-native';
3
+
4
+import WebView from 'react-native-webview';
5
+
6
+const HTML = `
7
+<!DOCTYPE html>\n
8
+<html>
9
+  <head>
10
+    <title>Alerts</title>
11
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
12
+    <meta name="viewport" content="width=320, user-scalable=no">
13
+    <style type="text/css">
14
+      body {
15
+        margin: 0;
16
+        padding: 0;
17
+        font: 62.5% arial, sans-serif;
18
+        background: #ccc;
19
+      }
20
+    </style>
21
+  </head>
22
+  <body>
23
+    <button onclick="showAlert()">Show alert</button>
24
+    <button onclick="showConfirm()">Show confirm</button>
25
+    <button onclick="showPrompt()">Show prompt</button>
26
+    <p id="demo"></p>    
27
+    <script>
28
+      function showAlert() {
29
+        alert("Hello! I am an alert box!");
30
+        document.getElementById("demo").innerHTML = "Alert dismissed!";
31
+      }
32
+      function showConfirm() {
33
+        var response;
34
+        if (confirm("Press a button!")) {
35
+          response = "You pressed OK on confirm!";
36
+        } else {
37
+          response = "You pressed Cancel on confirm!";
38
+        }
39
+        document.getElementById("demo").innerHTML = response;
40
+      }
41
+      function showPrompt() {
42
+        var message;
43
+        const name = prompt("Please enter your name", "Name");
44
+        if (name !== null) {
45
+          message = "Hello " + name;
46
+        } else {
47
+          message = "You pressed Cancel on prompt!";
48
+        }
49
+        document.getElementById("demo").innerHTML = message;
50
+      }
51
+    </script>
52
+  </body>
53
+</html>
54
+`;
55
+
56
+type Props = {};
57
+type State = {};
58
+
59
+export default class Alerts extends Component<Props, State> {
60
+  state = {};
61
+
62
+  render() {
63
+    return (
64
+      <View style={{ height: 120 }}>
65
+        <WebView
66
+          source={{html: HTML}}
67
+          automaticallyAdjustContentInsets={false}
68
+        />
69
+      </View>
70
+    );
71
+  }
72
+}

+ 54
- 0
example/examples/Background.tsx View File

1
+import React, {Component} from 'react';
2
+import {Text, View} from 'react-native';
3
+
4
+import WebView from 'react-native-webview';
5
+
6
+const HTML = `
7
+<!DOCTYPE html>\n
8
+<html>
9
+  <head>
10
+    <title>Hello World</title>
11
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
12
+    <meta name="viewport" content="width=320, user-scalable=no">
13
+    <style type="text/css">
14
+      body {
15
+        margin: 0;
16
+        padding: 0;
17
+        font: 62.5% arial, sans-serif;
18
+        background: transparent;
19
+      }
20
+    </style>
21
+  </head>
22
+  <body>
23
+    <p>HTML content in transparent body.</p>
24
+  </body>
25
+</html>
26
+`;
27
+
28
+type Props = {};
29
+type State = {
30
+  backgroundColor: string,
31
+};
32
+
33
+export default class Background extends Component<Props, State> {
34
+  state = {
35
+    backgroundColor: '#FF00FF00'
36
+  };
37
+
38
+  render() {
39
+    return (
40
+      <View>
41
+        <View style={{backgroundColor:'red'}}>
42
+          <View style={{ height: 120 }}>
43
+            <WebView
44
+              source={{html: HTML}}
45
+              automaticallyAdjustContentInsets={false}
46
+              style={{backgroundColor:'#00000000'}}
47
+            />
48
+          </View>
49
+        </View>
50
+        <Text>WebView is transparent contained in a View with a red backgroundColor</Text>
51
+      </View>
52
+    );
53
+  }
54
+}

+ 55
- 0
example/examples/Downloads.tsx View File

1
+import React, {Component} from 'react';
2
+import {Alert, Platform, View} from 'react-native';
3
+
4
+import WebView, {FileDownload} from 'react-native-webview';
5
+
6
+const HTML = `
7
+<!DOCTYPE html>\n
8
+<html>
9
+  <head>
10
+    <title>Downloads</title>
11
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
12
+    <meta name="viewport" content="width=320, user-scalable=no">
13
+    <style type="text/css">
14
+      body {
15
+        margin: 0;
16
+        padding: 0;
17
+        font: 62.5% arial, sans-serif;
18
+        background: #ccc;
19
+      }
20
+    </style>
21
+  </head>
22
+  <body>
23
+    <a href="https://www.7-zip.org/a/7za920.zip">Example zip file download</a>
24
+  </body>
25
+</html>
26
+`;
27
+
28
+type Props = {};
29
+type State = {};
30
+
31
+export default class Downloads extends Component<Props, State> {
32
+  state = {};
33
+
34
+  onFileDownload = ({ nativeEvent }: { nativeEvent: FileDownload } ) => {
35
+    Alert.alert("File download detected", nativeEvent.downloadUrl);
36
+  };
37
+
38
+  render() {
39
+    const platformProps = Platform.select({
40
+      ios: {
41
+        onFileDownload: this.onFileDownload,
42
+      },
43
+    });
44
+
45
+    return (
46
+      <View style={{ height: 120 }}>
47
+        <WebView
48
+          source={{html: HTML}}
49
+          automaticallyAdjustContentInsets={false}
50
+          {...platformProps}
51
+        />
52
+      </View>
53
+    );
54
+  }
55
+}

+ 160
- 0
example/examples/Injection.tsx View File

1
+import React, {Component} from 'react';
2
+import {Text, View, ScrollView} from 'react-native';
3
+
4
+import WebView from 'react-native-webview';
5
+
6
+// const HTML = `
7
+// <!DOCTYPE html>
8
+// <html>
9
+//   <head>
10
+//       <meta charset="utf-8">
11
+//       <meta name="viewport" content="width=device-width, initial-scale=1">
12
+//       <title>iframe test</title>
13
+//   </head>
14
+//   <body>
15
+//     <p style="">beforeContentLoaded on the top frame <span id="before_failed" style="display: inline-block;">failed</span><span id="before_succeeded" style="display: none;">succeeded</span>!</p>
16
+//     <p style="">afterContentLoaded on the top frame <span id="after_failed" style="display: inline-block;">failed</span><span id="after_succeeded" style="display: none;">succeeded</span>!</p>
17
+//     <iframe src="https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframe.html?v=1" name="iframe_0" style="width: 100%; height: 25px;"></iframe>
18
+//     <iframe src="https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframe2.html?v=1" name="iframe_1" style="width: 100%; height: 25px;"></iframe>
19
+//     <iframe src="https://www.ebay.co.uk" name="iframe_2" style="width: 100%; height: 25px;"></iframe>
20
+//   </body>
21
+// </html>
22
+// `;
23
+
24
+type Props = {};
25
+type State = {
26
+  backgroundColor: string,
27
+};
28
+
29
+export default class Injection extends Component<Props, State> {
30
+  state = {
31
+    backgroundColor: '#FF00FF00'
32
+  };
33
+
34
+  render() {
35
+    return (
36
+      <ScrollView>
37
+        <View style={{ }}>
38
+          <View style={{ height: 300 }}>
39
+            <WebView
40
+              /**
41
+               * This HTML is a copy of a multi-frame JS injection test that I had lying around.
42
+               * @see https://birchlabs.co.uk/linguabrowse/infopages/obsol/iframeTest.html
43
+               */
44
+              // source={{ html: HTML }}
45
+              source={{ uri: "https://birchlabs.co.uk/linguabrowse/infopages/obsol/rnw_iframe_test.html" }}
46
+              automaticallyAdjustContentInsets={false}
47
+              style={{backgroundColor:'#00000000'}}
48
+              
49
+              /* Must be populated in order for `messagingEnabled` to be `true` to activate the
50
+               * JS injection user scripts, consistent with current behaviour. This is undesirable,
51
+               * so needs addressing in a follow-up PR. */
52
+              onMessage={() => {}}
53
+
54
+              /* We set this property in each frame */
55
+              injectedJavaScriptBeforeContentLoaded={`
56
+              console.log("executing injectedJavaScriptBeforeContentLoaded...");
57
+              if(typeof window.top.injectedIframesBeforeContentLoaded === "undefined"){
58
+                window.top.injectedIframesBeforeContentLoaded = [];
59
+              }
60
+              window.self.colourToUse = "orange";
61
+              if(window.self === window.top){
62
+                console.log("Was window.top. window.frames.length is:", window.frames.length);
63
+                window.self.numberOfFramesAtBeforeContentLoaded = window.frames.length;
64
+                function declareSuccessOfBeforeContentLoaded(head){
65
+                  var style = window.self.document.createElement('style');
66
+                  style.type = 'text/css';
67
+                  style.innerHTML = "#before_failed { display: none !important; }#before_succeeded { display: inline-block !important; }";
68
+                  head.appendChild(style);
69
+                }
70
+
71
+                const head = (window.self.document.head || window.self.document.getElementsByTagName('head')[0]);
72
+
73
+                if(head){
74
+                  declareSuccessOfBeforeContentLoaded(head);
75
+                } else {
76
+                  window.self.document.addEventListener("DOMContentLoaded", function (event) {
77
+                    const head = (window.self.document.head || window.self.document.getElementsByTagName('head')[0]);
78
+                    declareSuccessOfBeforeContentLoaded(head);
79
+                  });
80
+                }
81
+              } else {
82
+                window.top.injectedIframesBeforeContentLoaded.push(window.self.name);
83
+                console.log("wasn't window.top.");
84
+                console.log("wasn't window.top. Still going...");
85
+              }
86
+              `}
87
+              
88
+              injectedJavaScriptForMainFrameOnly={false}
89
+
90
+              /* We read the colourToUse property in each frame to recolour each frame */
91
+              injectedJavaScript={`
92
+              console.log("executing injectedJavaScript...");
93
+              if(typeof window.top.injectedIframesAfterContentLoaded === "undefined"){
94
+                window.top.injectedIframesAfterContentLoaded = [];
95
+              }
96
+
97
+              if(window.self.colourToUse){
98
+                window.self.document.body.style.backgroundColor = window.self.colourToUse;
99
+              } else {
100
+                window.self.document.body.style.backgroundColor = "cyan";
101
+              }
102
+
103
+              if(window.self === window.top){
104
+                function declareSuccessOfAfterContentLoaded(head){
105
+                  var style = window.self.document.createElement('style');
106
+                  style.type = 'text/css';
107
+                  style.innerHTML = "#after_failed { display: none !important; }#after_succeeded { display: inline-block !important; }";
108
+                  head.appendChild(style);
109
+                }
110
+
111
+                declareSuccessOfAfterContentLoaded(window.self.document.head || window.self.document.getElementsByTagName('head')[0]);
112
+
113
+                // var numberOfFramesAtBeforeContentLoadedEle = document.createElement('p');
114
+                // numberOfFramesAtBeforeContentLoadedEle.textContent = "Number of iframes upon the main frame's beforeContentLoaded: " +
115
+                // window.self.numberOfFramesAtBeforeContentLoaded;
116
+
117
+                // var numberOfFramesAtAfterContentLoadedEle = document.createElement('p');
118
+                // numberOfFramesAtAfterContentLoadedEle.textContent = "Number of iframes upon the main frame's afterContentLoaded: " + window.frames.length;
119
+                // numberOfFramesAtAfterContentLoadedEle.id = "numberOfFramesAtAfterContentLoadedEle";
120
+
121
+                var namedFramesAtBeforeContentLoadedEle = document.createElement('p');
122
+                namedFramesAtBeforeContentLoadedEle.textContent = "Names of iframes that called beforeContentLoaded: " + JSON.stringify(window.top.injectedIframesBeforeContentLoaded);
123
+                namedFramesAtBeforeContentLoadedEle.id = "namedFramesAtBeforeContentLoadedEle";
124
+
125
+                var namedFramesAtAfterContentLoadedEle = document.createElement('p');
126
+                namedFramesAtAfterContentLoadedEle.textContent = "Names of iframes that called afterContentLoaded: " + JSON.stringify(window.top.injectedIframesAfterContentLoaded);
127
+                namedFramesAtAfterContentLoadedEle.id = "namedFramesAtAfterContentLoadedEle";
128
+
129
+                // document.body.appendChild(numberOfFramesAtBeforeContentLoadedEle);
130
+                // document.body.appendChild(numberOfFramesAtAfterContentLoadedEle);
131
+                document.body.appendChild(namedFramesAtBeforeContentLoadedEle);
132
+                document.body.appendChild(namedFramesAtAfterContentLoadedEle);
133
+              } else {
134
+                window.top.injectedIframesAfterContentLoaded.push(window.self.name);
135
+                window.top.document.getElementById('namedFramesAtAfterContentLoadedEle').textContent = "Names of iframes that called afterContentLoaded: " + JSON.stringify(window.top.injectedIframesAfterContentLoaded);
136
+              }
137
+              `}
138
+            />
139
+          </View>
140
+        </View>
141
+        <Text>This test presents three iframes: iframe_0 (yellow); iframe_1 (pink); and iframe_2 (transparent, because its 'X-Frame-Options' is set to 'SAMEORIGIN').</Text>
142
+        <Text>Before injection, the main frame's background is the browser's default value (transparent or white) and each frame has its natural colour.</Text>
143
+        {/*<Text>1a) At injection time "beforeContentLoaded", a variable will be set in each frame to set 'orange' as the "colour to be used".</Text>*/}
144
+        {/*<Text>1b) Also upon "beforeContentLoaded", a style element to change the text "beforeContentLoaded failed" -> "beforeContentLoaded succeeded" will be applied as soon as the head has loaded.</Text>*/}
145
+        {/*<Text>2a) At injection time "afterContentLoaded", that variable will be read – if present, the colour orange will be injected into all frames. Otherwise, cyan.</Text>*/}
146
+        {/*<Text>2b) Also upon "afterContentLoaded", a style element to change the text "afterContentLoaded failed" -> "afterContentLoaded succeeded" will be applied as soon as the head has loaded.</Text>*/}
147
+        <Text>✅ If the main frame becomes orange, then top-frame injection both beforeContentLoaded and afterContentLoaded is supported.</Text>
148
+        <Text>✅ If iframe_0, and iframe_1 become orange, then multi-frame injection beforeContentLoaded and afterContentLoaded is supported.</Text>
149
+        <Text>✅ If the two texts say "beforeContentLoaded on the top frame succeeded!" and "afterContentLoaded on the top frame succeeded!", then both injection times are supported at least on the main frame.</Text>
150
+        <Text>⚠️ If either of the two iframes become coloured cyan, then for that given frame, JS injection succeeded after the content loaded, but didn't occur before the content loaded - please note that for iframes, this may not be a test failure, as it is not clear whether we would expect iframes to support an injection time of beforeContentLoaded anyway.</Text>
151
+        <Text>⚠️ If "Names of iframes that called beforeContentLoaded: " is [], then see above.</Text>
152
+        <Text>❌ If "Names of iframes that called afterContentLoaded: " is [], then afterContentLoaded is not supported in iframes.</Text>
153
+        <Text>❌ If the main frame becomes coloured cyan, then JS injection succeeded after the content loaded, but didn't occur before the content loaded.</Text>
154
+        <Text>❌ If the text "beforeContentLoaded on the top frame failed" remains unchanged, then JS injection has failed on the main frame before the content loaded.</Text>
155
+        <Text>❌ If the text "afterContentLoaded on the top frame failed" remains unchanged, then JS injection has failed on the main frame after the content loaded.</Text>
156
+        <Text>❌ If the iframes remain their original colours (yellow and pink), then multi-frame injection is not supported at all.</Text>
157
+      </ScrollView>
158
+    );
159
+  }
160
+}

+ 16
- 0
example/examples/LocalPageLoad.tsx View File

1
+import React, {Component} from 'react';
2
+import {View, Text, Alert, TextInput, Button} from 'react-native';
3
+import WebView from 'react-native-webview';
4
+const localHtmlFile = require('../assets/test.html');
5
+
6
+export default class LocalPageLoad extends Component<Props, State> {
7
+    render() {
8
+      return (
9
+        <View>
10
+            <View style={{ width: '100%', height: '100%' }}>
11
+                <WebView source={localHtmlFile}/>
12
+          </View>
13
+        </View>
14
+      );
15
+    }
16
+  }

+ 68
- 0
example/examples/Scrolling.tsx View File

1
+import React, {Component} from 'react';
2
+import {Button, Text, View} from 'react-native';
3
+
4
+import WebView from 'react-native-webview';
5
+
6
+const HTML = `
7
+<!DOCTYPE html>\n
8
+<html>
9
+  <head>
10
+    <title>Hello World</title>
11
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
12
+    <meta name="viewport" content="width=320, user-scalable=no">
13
+    <style type="text/css">
14
+      body {
15
+        margin: 0;
16
+        padding: 0;
17
+        font: 62.5% arial, sans-serif;
18
+        background: #ccc;
19
+      }
20
+    </style>
21
+  </head>
22
+  <body>
23
+    <p>Lorem ipsum dolor sit amet, virtute utroque voluptaria et duo, probo aeque partiendo pri at. Mea ut stet aliquip deterruisset. Inani erroribus principes ei mel, no dicit recteque delicatissimi usu. Ne has dolore nominavi, feugait hendrerit interesset vis ea, amet regione ne pri. Te cum amet etiam.</p>
24
+    <p>Ut adipiscing neglegentur mediocritatem sea, suas abhorreant ius cu, ne nostrud feugiat per. Nam paulo facete iudicabit an, an brute mundi suavitate has, ex utamur numquam duo. Sea platonem argumentum instructior in, quo no prima inani perfecto. Ex illum postea copiosae has, ei mea sonet ocurreret.</p>
25
+    <p>Has convenire erroribus cu, quo homero facilisis inciderint ea. Vix choro gloriatur definitionem an, te exerci debitis voluptaria pri, mea admodum antiopam neglegentur te. His ea iisque splendide, nam id malorum pertinacia. Iusto tempor in eos, vis debet erant an. An nostrum rationibus sit, et sed dicta delenit suscipiantur. Est dolore vituperatoribus in, ubique explicari est cu. Legere tractatos ut usu, probo atqui vituperata in usu, mazim nemore praesent pro no.</p>
26
+    <p>Ei pri facilisi accusamus. Ut partem quaestio sit, an usu audiam quaerendum, ei qui hinc soleat. Fabulas phaedrum erroribus ut est. Intellegebat delicatissimi vis cu. His ea vidit libris facilis. Usu ne scripta legimus intellegam. Hendrerit urbanitas accommodare mei in.</p>
27
+    <p>Brute appetere efficiendi has ne. Ei ornatus labores vis. Vel harum fierent no, ad erat partiendo vis, harum democritum duo at. Has no labitur vulputate. Has cu autem aperiam hendrerit, sed eu justo verear menandri.</p>
28
+  </body>
29
+</html>
30
+`;
31
+
32
+type Props = {};
33
+type State = {
34
+  scrollEnabled: boolean,
35
+  lastScrollEvent: string
36
+};
37
+
38
+export default class Scrolling extends Component<Props, State> {
39
+  state = {
40
+    scrollEnabled: true,
41
+    lastScrollEvent: ''
42
+  };
43
+
44
+  render() {
45
+    return (
46
+      <View>
47
+        <View style={{ height: 120 }}>
48
+          <WebView
49
+            source={{html: HTML}}
50
+            automaticallyAdjustContentInsets={false}
51
+            onScroll={this._onScroll}
52
+            scrollEnabled={this.state.scrollEnabled}
53
+          />
54
+        </View>
55
+        <Button
56
+          title={this.state.scrollEnabled ? 'Scroll enabled' : 'Scroll disabled'}
57
+          onPress={() => this.setState({scrollEnabled: !this.state.scrollEnabled})}
58
+        />
59
+        <Text>Last scroll event:</Text>
60
+        <Text>{this.state.lastScrollEvent}</Text>
61
+      </View>
62
+    );
63
+  }
64
+
65
+  _onScroll = event => {
66
+    this.setState({lastScrollEvent: JSON.stringify(event.nativeEvent)});
67
+  }
68
+}

+ 69
- 0
example/examples/Uploads.tsx View File

1
+import React, {Component} from 'react';
2
+import {Button, Linking, Text, View} from 'react-native';
3
+
4
+import WebView from 'react-native-webview';
5
+
6
+const HTML = `
7
+<!DOCTYPE html>\n
8
+<html>
9
+  <head>
10
+    <title>Uploads</title>
11
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
12
+    <meta name="viewport" content="width=320, user-scalable=no">
13
+    <style type="text/css">
14
+      body {
15
+        margin: 0;
16
+        padding: 0;
17
+        font: 62.5% arial, sans-serif;
18
+        background: #ccc;
19
+      }
20
+    </style>
21
+  </head>
22
+  <body>
23
+    <p>
24
+      <label for="images-only">Images only file upload</label>
25
+      <input name="images-only" type="file" accept="image/*">
26
+    </p>
27
+    <p>
28
+      <label for="video-only">Video only file upload</label>
29
+      <input name="video-only" type="file" accept="video/*">
30
+    </p>
31
+    <p>
32
+      <label for="any-file">Any file upload</label>
33
+      <input name="any-file" type="file">
34
+    </p>
35
+  </body>
36
+</html>
37
+`;
38
+
39
+type Props = {};
40
+type State = {};
41
+
42
+export default class Uploads extends Component<Props, State> {
43
+  state = {};
44
+
45
+  render() {
46
+    return (
47
+      <View>
48
+        <View style={{ height: 120 }}>
49
+          <WebView
50
+            source={{html: HTML}}
51
+            automaticallyAdjustContentInsets={false}
52
+          />
53
+        </View>
54
+        <Text>
55
+            Android limitation: If the file input should show camera options for the user,
56
+            and the app has the ability to request the camera permission, then the user must
57
+            grant permission first in order to see the options. Since this example app does
58
+            have the permission declared, you must allow it in settings to be able to see
59
+            camera options. If your app does not have the camera permission declared, then
60
+            there is no restriction to showing the camera options.
61
+        </Text>
62
+        <Button
63
+          title="Open settings"
64
+          onPress={() => Linking.openSettings()}
65
+        />
66
+      </View>
67
+    );
68
+  }
69
+}

+ 9
- 0
example/index.js View File

1
+/**
2
+ * @format
3
+ */
4
+
5
+import {AppRegistry} from 'react-native';
6
+import App from './App';
7
+import {name as appName} from './app.json';
8
+
9
+AppRegistry.registerComponent(appName, () => App);

+ 56
- 0
example/ios/Podfile View File

1
+platform :ios, '9.0'
2
+require_relative '../../node_modules/@react-native-community/cli-platform-ios/native_modules'
3
+
4
+project './example.xcodeproj'
5
+
6
+target 'example' do
7
+  use_native_modules!
8
+
9
+  pod 'react-native-webview', :path => "../.."
10
+
11
+  pod 'FBLazyVector', :path => "../../node_modules/react-native/Libraries/FBLazyVector"
12
+  pod 'FBReactNativeSpec', :path => "../../node_modules/react-native/Libraries/FBReactNativeSpec"
13
+  pod 'RCTRequired', :path => "../../node_modules/react-native/Libraries/RCTRequired"
14
+  pod 'RCTTypeSafety', :path => "../../node_modules/react-native/Libraries/TypeSafety"
15
+  pod 'React', :path => '../../node_modules/react-native/'
16
+  pod 'React-Core', :path => '../../node_modules/react-native/'
17
+  pod 'React-CoreModules', :path => '../../node_modules/react-native/React/CoreModules'
18
+  pod 'React-Core/DevSupport', :path => '../../node_modules/react-native/'
19
+  pod 'React-RCTActionSheet', :path => '../../node_modules/react-native/Libraries/ActionSheetIOS'
20
+  pod 'React-RCTAnimation', :path => '../../node_modules/react-native/Libraries/NativeAnimation'
21
+  pod 'React-RCTBlob', :path => '../../node_modules/react-native/Libraries/Blob'
22
+  pod 'React-RCTImage', :path => '../../node_modules/react-native/Libraries/Image'
23
+  pod 'React-RCTLinking', :path => '../../node_modules/react-native/Libraries/LinkingIOS'
24
+  pod 'React-RCTNetwork', :path => '../../node_modules/react-native/Libraries/Network'
25
+  pod 'React-RCTSettings', :path => '../../node_modules/react-native/Libraries/Settings'
26
+  pod 'React-RCTText', :path => '../../node_modules/react-native/Libraries/Text'
27
+  pod 'React-RCTVibration', :path => '../../node_modules/react-native/Libraries/Vibration'
28
+  pod 'React-Core/RCTWebSocket', :path => '../../node_modules/react-native/'
29
+
30
+  pod 'React-cxxreact', :path => '../../node_modules/react-native/ReactCommon/cxxreact'
31
+  pod 'React-jsi', :path => '../../node_modules/react-native/ReactCommon/jsi'
32
+  pod 'React-jsiexecutor', :path => '../../node_modules/react-native/ReactCommon/jsiexecutor'
33
+  pod 'React-jsinspector', :path => '../../node_modules/react-native/ReactCommon/jsinspector'
34
+  pod 'ReactCommon/callinvoker', :path => "../../node_modules/react-native/ReactCommon"
35
+  pod 'ReactCommon/turbomodule/core', :path => "../../node_modules/react-native/ReactCommon"
36
+  pod 'Yoga', :path => '../../node_modules/react-native/ReactCommon/yoga', :modular_headers => true
37
+
38
+  pod 'DoubleConversion', :podspec => '../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
39
+  pod 'glog', :podspec => '../../node_modules/react-native/third-party-podspecs/glog.podspec'
40
+  pod 'Folly', :podspec => '../../node_modules/react-native/third-party-podspecs/Folly.podspec'
41
+
42
+  target 'exampleTests' do
43
+    inherit! :search_paths
44
+    # Pods for testing
45
+  end
46
+end
47
+
48
+target 'example-tvOS' do
49
+  # Pods for example-tvOS
50
+
51
+  target 'example-tvOSTests' do
52
+    inherit! :complete
53
+    # Pods for testing
54
+  end
55
+
56
+end

+ 368
- 0
example/ios/Podfile.lock View File

1
+PODS:
2
+  - boost-for-react-native (1.63.0)
3
+  - DoubleConversion (1.1.6)
4
+  - FBLazyVector (0.62.2)
5
+  - FBReactNativeSpec (0.62.2):
6
+    - Folly (= 2018.10.22.00)
7
+    - RCTRequired (= 0.62.2)
8
+    - RCTTypeSafety (= 0.62.2)
9
+    - React-Core (= 0.62.2)
10
+    - React-jsi (= 0.62.2)
11
+    - ReactCommon/turbomodule/core (= 0.62.2)
12
+  - Folly (2018.10.22.00):
13
+    - boost-for-react-native
14
+    - DoubleConversion
15
+    - Folly/Default (= 2018.10.22.00)
16
+    - glog
17
+  - Folly/Default (2018.10.22.00):
18
+    - boost-for-react-native
19
+    - DoubleConversion
20
+    - glog
21
+  - glog (0.3.5)
22
+  - RCTRequired (0.62.2)
23
+  - RCTTypeSafety (0.62.2):
24
+    - FBLazyVector (= 0.62.2)
25
+    - Folly (= 2018.10.22.00)
26
+    - RCTRequired (= 0.62.2)
27
+    - React-Core (= 0.62.2)
28
+  - React (0.62.2):
29
+    - React-Core (= 0.62.2)
30
+    - React-Core/DevSupport (= 0.62.2)
31
+    - React-Core/RCTWebSocket (= 0.62.2)
32
+    - React-RCTActionSheet (= 0.62.2)
33
+    - React-RCTAnimation (= 0.62.2)
34
+    - React-RCTBlob (= 0.62.2)
35
+    - React-RCTImage (= 0.62.2)
36
+    - React-RCTLinking (= 0.62.2)
37
+    - React-RCTNetwork (= 0.62.2)
38
+    - React-RCTSettings (= 0.62.2)
39
+    - React-RCTText (= 0.62.2)
40
+    - React-RCTVibration (= 0.62.2)
41
+  - React-Core (0.62.2):
42
+    - Folly (= 2018.10.22.00)
43
+    - glog
44
+    - React-Core/Default (= 0.62.2)
45
+    - React-cxxreact (= 0.62.2)
46
+    - React-jsi (= 0.62.2)
47
+    - React-jsiexecutor (= 0.62.2)
48
+    - Yoga
49
+  - React-Core/CoreModulesHeaders (0.62.2):
50
+    - Folly (= 2018.10.22.00)
51
+    - glog
52
+    - React-Core/Default
53
+    - React-cxxreact (= 0.62.2)
54
+    - React-jsi (= 0.62.2)
55
+    - React-jsiexecutor (= 0.62.2)
56
+    - Yoga
57
+  - React-Core/Default (0.62.2):
58
+    - Folly (= 2018.10.22.00)
59
+    - glog
60
+    - React-cxxreact (= 0.62.2)
61
+    - React-jsi (= 0.62.2)
62
+    - React-jsiexecutor (= 0.62.2)
63
+    - Yoga
64
+  - React-Core/DevSupport (0.62.2):
65
+    - Folly (= 2018.10.22.00)
66
+    - glog
67
+    - React-Core/Default (= 0.62.2)
68
+    - React-Core/RCTWebSocket (= 0.62.2)
69
+    - React-cxxreact (= 0.62.2)
70
+    - React-jsi (= 0.62.2)
71
+    - React-jsiexecutor (= 0.62.2)
72
+    - React-jsinspector (= 0.62.2)
73
+    - Yoga
74
+  - React-Core/RCTActionSheetHeaders (0.62.2):
75
+    - Folly (= 2018.10.22.00)
76
+    - glog
77
+    - React-Core/Default
78
+    - React-cxxreact (= 0.62.2)
79
+    - React-jsi (= 0.62.2)
80
+    - React-jsiexecutor (= 0.62.2)
81
+    - Yoga
82
+  - React-Core/RCTAnimationHeaders (0.62.2):
83
+    - Folly (= 2018.10.22.00)
84
+    - glog
85
+    - React-Core/Default
86
+    - React-cxxreact (= 0.62.2)
87
+    - React-jsi (= 0.62.2)
88
+    - React-jsiexecutor (= 0.62.2)
89
+    - Yoga
90
+  - React-Core/RCTBlobHeaders (0.62.2):
91
+    - Folly (= 2018.10.22.00)
92
+    - glog
93
+    - React-Core/Default
94
+    - React-cxxreact (= 0.62.2)
95
+    - React-jsi (= 0.62.2)
96
+    - React-jsiexecutor (= 0.62.2)
97
+    - Yoga
98
+  - React-Core/RCTImageHeaders (0.62.2):
99
+    - Folly (= 2018.10.22.00)
100
+    - glog
101
+    - React-Core/Default
102
+    - React-cxxreact (= 0.62.2)
103
+    - React-jsi (= 0.62.2)
104
+    - React-jsiexecutor (= 0.62.2)
105
+    - Yoga
106
+  - React-Core/RCTLinkingHeaders (0.62.2):
107
+    - Folly (= 2018.10.22.00)
108
+    - glog
109
+    - React-Core/Default
110
+    - React-cxxreact (= 0.62.2)
111
+    - React-jsi (= 0.62.2)
112
+    - React-jsiexecutor (= 0.62.2)
113
+    - Yoga
114
+  - React-Core/RCTNetworkHeaders (0.62.2):
115
+    - Folly (= 2018.10.22.00)
116
+    - glog
117
+    - React-Core/Default
118
+    - React-cxxreact (= 0.62.2)
119
+    - React-jsi (= 0.62.2)
120
+    - React-jsiexecutor (= 0.62.2)
121
+    - Yoga
122
+  - React-Core/RCTSettingsHeaders (0.62.2):
123
+    - Folly (= 2018.10.22.00)
124
+    - glog
125
+    - React-Core/Default
126
+    - React-cxxreact (= 0.62.2)
127
+    - React-jsi (= 0.62.2)
128
+    - React-jsiexecutor (= 0.62.2)
129
+    - Yoga
130
+  - React-Core/RCTTextHeaders (0.62.2):
131
+    - Folly (= 2018.10.22.00)
132
+    - glog
133
+    - React-Core/Default
134
+    - React-cxxreact (= 0.62.2)
135
+    - React-jsi (= 0.62.2)
136
+    - React-jsiexecutor (= 0.62.2)
137
+    - Yoga
138
+  - React-Core/RCTVibrationHeaders (0.62.2):
139
+    - Folly (= 2018.10.22.00)
140
+    - glog
141
+    - React-Core/Default
142
+    - React-cxxreact (= 0.62.2)
143
+    - React-jsi (= 0.62.2)
144
+    - React-jsiexecutor (= 0.62.2)
145
+    - Yoga
146
+  - React-Core/RCTWebSocket (0.62.2):
147
+    - Folly (= 2018.10.22.00)
148
+    - glog
149
+    - React-Core/Default (= 0.62.2)
150
+    - React-cxxreact (= 0.62.2)
151
+    - React-jsi (= 0.62.2)
152
+    - React-jsiexecutor (= 0.62.2)
153
+    - Yoga
154
+  - React-CoreModules (0.62.2):
155
+    - FBReactNativeSpec (= 0.62.2)
156
+    - Folly (= 2018.10.22.00)
157
+    - RCTTypeSafety (= 0.62.2)
158
+    - React-Core/CoreModulesHeaders (= 0.62.2)
159
+    - React-RCTImage (= 0.62.2)
160
+    - ReactCommon/turbomodule/core (= 0.62.2)
161
+  - React-cxxreact (0.62.2):
162
+    - boost-for-react-native (= 1.63.0)
163
+    - DoubleConversion
164
+    - Folly (= 2018.10.22.00)
165
+    - glog
166
+    - React-jsinspector (= 0.62.2)
167
+  - React-jsi (0.62.2):
168
+    - boost-for-react-native (= 1.63.0)
169
+    - DoubleConversion
170
+    - Folly (= 2018.10.22.00)
171
+    - glog
172
+    - React-jsi/Default (= 0.62.2)
173
+  - React-jsi/Default (0.62.2):
174
+    - boost-for-react-native (= 1.63.0)
175
+    - DoubleConversion
176
+    - Folly (= 2018.10.22.00)
177
+    - glog
178
+  - React-jsiexecutor (0.62.2):
179
+    - DoubleConversion
180
+    - Folly (= 2018.10.22.00)
181
+    - glog
182
+    - React-cxxreact (= 0.62.2)
183
+    - React-jsi (= 0.62.2)
184
+  - React-jsinspector (0.62.2)
185
+  - react-native-webview (9.4.0):
186
+    - React
187
+  - React-RCTActionSheet (0.62.2):
188
+    - React-Core/RCTActionSheetHeaders (= 0.62.2)
189
+  - React-RCTAnimation (0.62.2):
190
+    - FBReactNativeSpec (= 0.62.2)
191
+    - Folly (= 2018.10.22.00)
192
+    - RCTTypeSafety (= 0.62.2)
193
+    - React-Core/RCTAnimationHeaders (= 0.62.2)
194
+    - ReactCommon/turbomodule/core (= 0.62.2)
195
+  - React-RCTBlob (0.62.2):
196
+    - FBReactNativeSpec (= 0.62.2)
197
+    - Folly (= 2018.10.22.00)
198
+    - React-Core/RCTBlobHeaders (= 0.62.2)
199
+    - React-Core/RCTWebSocket (= 0.62.2)
200
+    - React-jsi (= 0.62.2)
201
+    - React-RCTNetwork (= 0.62.2)
202
+    - ReactCommon/turbomodule/core (= 0.62.2)
203
+  - React-RCTImage (0.62.2):
204
+    - FBReactNativeSpec (= 0.62.2)
205
+    - Folly (= 2018.10.22.00)
206
+    - RCTTypeSafety (= 0.62.2)
207
+    - React-Core/RCTImageHeaders (= 0.62.2)
208
+    - React-RCTNetwork (= 0.62.2)
209
+    - ReactCommon/turbomodule/core (= 0.62.2)
210
+  - React-RCTLinking (0.62.2):
211
+    - FBReactNativeSpec (= 0.62.2)
212
+    - React-Core/RCTLinkingHeaders (= 0.62.2)
213
+    - ReactCommon/turbomodule/core (= 0.62.2)
214
+  - React-RCTNetwork (0.62.2):
215
+    - FBReactNativeSpec (= 0.62.2)
216
+    - Folly (= 2018.10.22.00)
217
+    - RCTTypeSafety (= 0.62.2)
218
+    - React-Core/RCTNetworkHeaders (= 0.62.2)
219
+    - ReactCommon/turbomodule/core (= 0.62.2)
220
+  - React-RCTSettings (0.62.2):
221
+    - FBReactNativeSpec (= 0.62.2)
222
+    - Folly (= 2018.10.22.00)
223
+    - RCTTypeSafety (= 0.62.2)
224
+    - React-Core/RCTSettingsHeaders (= 0.62.2)
225
+    - ReactCommon/turbomodule/core (= 0.62.2)
226
+  - React-RCTText (0.62.2):
227
+    - React-Core/RCTTextHeaders (= 0.62.2)
228
+  - React-RCTVibration (0.62.2):
229
+    - FBReactNativeSpec (= 0.62.2)
230
+    - Folly (= 2018.10.22.00)
231
+    - React-Core/RCTVibrationHeaders (= 0.62.2)
232
+    - ReactCommon/turbomodule/core (= 0.62.2)
233
+  - ReactCommon/callinvoker (0.62.2):
234
+    - DoubleConversion
235
+    - Folly (= 2018.10.22.00)
236
+    - glog
237
+    - React-cxxreact (= 0.62.2)
238
+  - ReactCommon/turbomodule/core (0.62.2):
239
+    - DoubleConversion
240
+    - Folly (= 2018.10.22.00)
241
+    - glog
242
+    - React-Core (= 0.62.2)
243
+    - React-cxxreact (= 0.62.2)
244
+    - React-jsi (= 0.62.2)
245
+    - ReactCommon/callinvoker (= 0.62.2)
246
+  - Yoga (1.14.0)
247
+
248
+DEPENDENCIES:
249
+  - DoubleConversion (from `../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
250
+  - FBLazyVector (from `../../node_modules/react-native/Libraries/FBLazyVector`)
251
+  - FBReactNativeSpec (from `../../node_modules/react-native/Libraries/FBReactNativeSpec`)
252
+  - Folly (from `../../node_modules/react-native/third-party-podspecs/Folly.podspec`)
253
+  - glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
254
+  - RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`)
255
+  - RCTTypeSafety (from `../../node_modules/react-native/Libraries/TypeSafety`)
256
+  - React (from `../../node_modules/react-native/`)
257
+  - React-Core (from `../../node_modules/react-native/`)
258
+  - React-Core/DevSupport (from `../../node_modules/react-native/`)
259
+  - React-Core/RCTWebSocket (from `../../node_modules/react-native/`)
260
+  - React-CoreModules (from `../../node_modules/react-native/React/CoreModules`)
261
+  - React-cxxreact (from `../../node_modules/react-native/ReactCommon/cxxreact`)
262
+  - React-jsi (from `../../node_modules/react-native/ReactCommon/jsi`)
263
+  - React-jsiexecutor (from `../../node_modules/react-native/ReactCommon/jsiexecutor`)
264
+  - React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`)
265
+  - react-native-webview (from `../..`)
266
+  - React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`)
267
+  - React-RCTAnimation (from `../../node_modules/react-native/Libraries/NativeAnimation`)
268
+  - React-RCTBlob (from `../../node_modules/react-native/Libraries/Blob`)
269
+  - React-RCTImage (from `../../node_modules/react-native/Libraries/Image`)
270
+  - React-RCTLinking (from `../../node_modules/react-native/Libraries/LinkingIOS`)
271
+  - React-RCTNetwork (from `../../node_modules/react-native/Libraries/Network`)
272
+  - React-RCTSettings (from `../../node_modules/react-native/Libraries/Settings`)
273
+  - React-RCTText (from `../../node_modules/react-native/Libraries/Text`)
274
+  - React-RCTVibration (from `../../node_modules/react-native/Libraries/Vibration`)
275
+  - ReactCommon/callinvoker (from `../../node_modules/react-native/ReactCommon`)
276
+  - ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`)
277
+  - Yoga (from `../../node_modules/react-native/ReactCommon/yoga`)
278
+
279
+SPEC REPOS:
280
+  trunk:
281
+    - boost-for-react-native
282
+
283
+EXTERNAL SOURCES:
284
+  DoubleConversion:
285
+    :podspec: "../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
286
+  FBLazyVector:
287
+    :path: "../../node_modules/react-native/Libraries/FBLazyVector"
288
+  FBReactNativeSpec:
289
+    :path: "../../node_modules/react-native/Libraries/FBReactNativeSpec"
290
+  Folly:
291
+    :podspec: "../../node_modules/react-native/third-party-podspecs/Folly.podspec"
292
+  glog:
293
+    :podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec"
294
+  RCTRequired:
295
+    :path: "../../node_modules/react-native/Libraries/RCTRequired"
296
+  RCTTypeSafety:
297
+    :path: "../../node_modules/react-native/Libraries/TypeSafety"
298
+  React:
299
+    :path: "../../node_modules/react-native/"
300
+  React-Core:
301
+    :path: "../../node_modules/react-native/"
302
+  React-CoreModules:
303
+    :path: "../../node_modules/react-native/React/CoreModules"
304
+  React-cxxreact:
305
+    :path: "../../node_modules/react-native/ReactCommon/cxxreact"
306
+  React-jsi:
307
+    :path: "../../node_modules/react-native/ReactCommon/jsi"
308
+  React-jsiexecutor:
309
+    :path: "../../node_modules/react-native/ReactCommon/jsiexecutor"
310
+  React-jsinspector:
311
+    :path: "../../node_modules/react-native/ReactCommon/jsinspector"
312
+  react-native-webview:
313
+    :path: "../.."
314
+  React-RCTActionSheet:
315
+    :path: "../../node_modules/react-native/Libraries/ActionSheetIOS"
316
+  React-RCTAnimation:
317
+    :path: "../../node_modules/react-native/Libraries/NativeAnimation"
318
+  React-RCTBlob:
319
+    :path: "../../node_modules/react-native/Libraries/Blob"
320
+  React-RCTImage:
321
+    :path: "../../node_modules/react-native/Libraries/Image"
322
+  React-RCTLinking:
323
+    :path: "../../node_modules/react-native/Libraries/LinkingIOS"
324
+  React-RCTNetwork:
325
+    :path: "../../node_modules/react-native/Libraries/Network"
326
+  React-RCTSettings:
327
+    :path: "../../node_modules/react-native/Libraries/Settings"
328
+  React-RCTText:
329
+    :path: "../../node_modules/react-native/Libraries/Text"
330
+  React-RCTVibration:
331
+    :path: "../../node_modules/react-native/Libraries/Vibration"
332
+  ReactCommon:
333
+    :path: "../../node_modules/react-native/ReactCommon"
334
+  Yoga:
335
+    :path: "../../node_modules/react-native/ReactCommon/yoga"
336
+
337
+SPEC CHECKSUMS:
338
+  boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
339
+  DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
340
+  FBLazyVector: 4aab18c93cd9546e4bfed752b4084585eca8b245
341
+  FBReactNativeSpec: 5465d51ccfeecb7faa12f9ae0024f2044ce4044e
342
+  Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
343
+  glog: 1f3da668190260b06b429bb211bfbee5cd790c28
344
+  RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035
345
+  RCTTypeSafety: 93006131180074cffa227a1075802c89a49dd4ce
346
+  React: 29a8b1a02bd764fb7644ef04019270849b9a7ac3
347
+  React-Core: b12bffb3f567fdf99510acb716ef1abd426e0e05
348
+  React-CoreModules: 4a9b87bbe669d6c3173c0132c3328e3b000783d0
349
+  React-cxxreact: e65f9c2ba0ac5be946f53548c1aaaee5873a8103
350
+  React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161
351
+  React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
352
+  React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
353
+  react-native-webview: cf5527893252b3b036eea024a1da6996f7344c74
354
+  React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
355
+  React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
356
+  React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
357
+  React-RCTImage: e70be9b9c74fe4e42d0005f42cace7981c994ac3
358
+  React-RCTLinking: c1b9739a88d56ecbec23b7f63650e44672ab2ad2
359
+  React-RCTNetwork: 73138b6f45e5a2768ad93f3d57873c2a18d14b44
360
+  React-RCTSettings: 6e3738a87e21b39a8cb08d627e68c44acf1e325a
361
+  React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d
362
+  React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256
363
+  ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3
364
+  Yoga: 3ebccbdd559724312790e7742142d062476b698e
365
+
366
+PODFILE CHECKSUM: 767ae042fafc1aba97b301c58c340ff6f992aa27
367
+
368
+COCOAPODS: 1.9.1

+ 53
- 0
example/ios/example-tvOS/Info.plist View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleExecutable</key>
8
+	<string>$(EXECUTABLE_NAME)</string>
9
+	<key>CFBundleIdentifier</key>
10
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+	<key>CFBundleInfoDictionaryVersion</key>
12
+	<string>6.0</string>
13
+	<key>CFBundleName</key>
14
+	<string>$(PRODUCT_NAME)</string>
15
+	<key>CFBundlePackageType</key>
16
+	<string>APPL</string>
17
+	<key>CFBundleShortVersionString</key>
18
+	<string>1.0</string>
19
+	<key>CFBundleSignature</key>
20
+	<string>????</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+	<key>LSRequiresIPhoneOS</key>
24
+	<true/>
25
+	<key>NSAppTransportSecurity</key>
26
+	<dict>
27
+		<key>NSExceptionDomains</key>
28
+		<dict>
29
+			<key>localhost</key>
30
+			<dict>
31
+				<key>NSExceptionAllowsInsecureHTTPLoads</key>
32
+				<true/>
33
+			</dict>
34
+		</dict>
35
+	</dict>
36
+	<key>NSLocationWhenInUseUsageDescription</key>
37
+	<string></string>
38
+	<key>UILaunchStoryboardName</key>
39
+	<string>LaunchScreen</string>
40
+	<key>UIRequiredDeviceCapabilities</key>
41
+	<array>
42
+		<string>armv7</string>
43
+	</array>
44
+	<key>UISupportedInterfaceOrientations</key>
45
+	<array>
46
+		<string>UIInterfaceOrientationPortrait</string>
47
+		<string>UIInterfaceOrientationLandscapeLeft</string>
48
+		<string>UIInterfaceOrientationLandscapeRight</string>
49
+	</array>
50
+	<key>UIViewControllerBasedStatusBarAppearance</key>
51
+	<false/>
52
+</dict>
53
+</plist>

+ 24
- 0
example/ios/example-tvOSTests/Info.plist View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleExecutable</key>
8
+	<string>$(EXECUTABLE_NAME)</string>
9
+	<key>CFBundleIdentifier</key>
10
+	<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
11
+	<key>CFBundleInfoDictionaryVersion</key>
12
+	<string>6.0</string>
13
+	<key>CFBundleName</key>
14
+	<string>$(PRODUCT_NAME)</string>
15
+	<key>CFBundlePackageType</key>
16
+	<string>BNDL</string>
17
+	<key>CFBundleShortVersionString</key>
18
+	<string>1.0</string>
19
+	<key>CFBundleSignature</key>
20
+	<string>????</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+</dict>
24
+</plist>

+ 929
- 0
example/ios/example.xcodeproj/project.pbxproj View File

1
+// !$*UTF8*$!
2
+{
3
+	archiveVersion = 1;
4
+	classes = {
5
+	};
6
+	objectVersion = 46;
7
+	objects = {
8
+
9
+/* Begin PBXBuildFile section */
10
+		00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };
11
+		13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
12
+		13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13
+		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
14
+		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
15
+		2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
16
+		2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
17
+		2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
18
+		2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };
19
+		646BD8E8CDDF5A464B5419B3 /* libPods-example-tvOS-example-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4830F7139A954350DD22DE4A /* libPods-example-tvOS-example-tvOSTests.a */; };
20
+		C7D826CF866C25BE421302B6 /* libPods-example-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F9A8A9F158876EC099CFA57A /* libPods-example-tvOS.a */; };
21
+		D0E3313DFCE78BFCB650F812 /* libPods-exampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CB301596D47BBAD9E9C0A45A /* libPods-exampleTests.a */; };
22
+		E719A6E171791CD8906B3D55 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 917A19FC1EBE6E8B85FE404D /* libPods-example.a */; };
23
+/* End PBXBuildFile section */
24
+
25
+/* Begin PBXContainerItemProxy section */
26
+		00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
27
+			isa = PBXContainerItemProxy;
28
+			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
29
+			proxyType = 1;
30
+			remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
31
+			remoteInfo = example;
32
+		};
33
+		2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
34
+			isa = PBXContainerItemProxy;
35
+			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
36
+			proxyType = 1;
37
+			remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
38
+			remoteInfo = "example-tvOS";
39
+		};
40
+/* End PBXContainerItemProxy section */
41
+
42
+/* Begin PBXFileReference section */
43
+		008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
44
+		00E356EE1AD99517003FC87E /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
45
+		00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
46
+		00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; sourceTree = "<group>"; };
47
+		13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; };
48
+		13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = "<group>"; };
49
+		13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/AppDelegate.m; sourceTree = "<group>"; };
50
+		13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
51
+		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = "<group>"; };
52
+		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = "<group>"; };
53
+		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = "<group>"; };
54
+		2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
55
+		2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
56
+		41B6A4553C4F552488B69B01 /* Pods-exampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-exampleTests.release.xcconfig"; path = "Target Support Files/Pods-exampleTests/Pods-exampleTests.release.xcconfig"; sourceTree = "<group>"; };
57
+		4372A2FD2D749DE5C9FD8D3E /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; };
58
+		4830F7139A954350DD22DE4A /* libPods-example-tvOS-example-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOS-example-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
59
+		4FDD34C422D711AC8A7B10A7 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; };
60
+		59A4F27CAD1B7EFE80917453 /* Pods-example-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
61
+		6517B8E7187010A1D58A96EE /* Pods-example-tvOS-example-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS-example-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOS-example-tvOSTests/Pods-example-tvOS-example-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
62
+		775F6B7492793F5DB7ECE95B /* Pods-example-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
63
+		8A20011E75A0AD2EC5C6EAE9 /* Pods-exampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-exampleTests.debug.xcconfig"; path = "Target Support Files/Pods-exampleTests/Pods-exampleTests.debug.xcconfig"; sourceTree = "<group>"; };
64
+		917A19FC1EBE6E8B85FE404D /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
65
+		CB301596D47BBAD9E9C0A45A /* libPods-exampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-exampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
66
+		ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
67
+		ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
68
+		EDF80BE96CF92848F4E926EA /* Pods-example-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.release.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.release.xcconfig"; sourceTree = "<group>"; };
69
+		EE3925F4209E17ECF3E692D1 /* Pods-example-tvOS-example-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS-example-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-example-tvOS-example-tvOSTests/Pods-example-tvOS-example-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
70
+		F67BC8D73DE103BA10A5488D /* Pods-example-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
71
+		F9A8A9F158876EC099CFA57A /* libPods-example-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
72
+/* End PBXFileReference section */
73
+
74
+/* Begin PBXFrameworksBuildPhase section */
75
+		00E356EB1AD99517003FC87E /* Frameworks */ = {
76
+			isa = PBXFrameworksBuildPhase;
77
+			buildActionMask = 2147483647;
78
+			files = (
79
+				D0E3313DFCE78BFCB650F812 /* libPods-exampleTests.a in Frameworks */,
80
+			);
81
+			runOnlyForDeploymentPostprocessing = 0;
82
+		};
83
+		13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
84
+			isa = PBXFrameworksBuildPhase;
85
+			buildActionMask = 2147483647;
86
+			files = (
87
+				E719A6E171791CD8906B3D55 /* libPods-example.a in Frameworks */,
88
+			);
89
+			runOnlyForDeploymentPostprocessing = 0;
90
+		};
91
+		2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
92
+			isa = PBXFrameworksBuildPhase;
93
+			buildActionMask = 2147483647;
94
+			files = (
95
+				C7D826CF866C25BE421302B6 /* libPods-example-tvOS.a in Frameworks */,
96
+			);
97
+			runOnlyForDeploymentPostprocessing = 0;
98
+		};
99
+		2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
100
+			isa = PBXFrameworksBuildPhase;
101
+			buildActionMask = 2147483647;
102
+			files = (
103
+				646BD8E8CDDF5A464B5419B3 /* libPods-example-tvOS-example-tvOSTests.a in Frameworks */,
104
+			);
105
+			runOnlyForDeploymentPostprocessing = 0;
106
+		};
107
+/* End PBXFrameworksBuildPhase section */
108
+
109
+/* Begin PBXGroup section */
110
+		00E356EF1AD99517003FC87E /* exampleTests */ = {
111
+			isa = PBXGroup;
112
+			children = (
113
+				00E356F21AD99517003FC87E /* exampleTests.m */,
114
+				00E356F01AD99517003FC87E /* Supporting Files */,
115
+			);
116
+			path = exampleTests;
117
+			sourceTree = "<group>";
118
+		};
119
+		00E356F01AD99517003FC87E /* Supporting Files */ = {
120
+			isa = PBXGroup;
121
+			children = (
122
+				00E356F11AD99517003FC87E /* Info.plist */,
123
+			);
124
+			name = "Supporting Files";
125
+			sourceTree = "<group>";
126
+		};
127
+		13B07FAE1A68108700A75B9A /* example */ = {
128
+			isa = PBXGroup;
129
+			children = (
130
+				008F07F21AC5B25A0029DE68 /* main.jsbundle */,
131
+				13B07FAF1A68108700A75B9A /* AppDelegate.h */,
132
+				13B07FB01A68108700A75B9A /* AppDelegate.m */,
133
+				13B07FB51A68108700A75B9A /* Images.xcassets */,
134
+				13B07FB61A68108700A75B9A /* Info.plist */,
135
+				13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
136
+				13B07FB71A68108700A75B9A /* main.m */,
137
+			);
138
+			name = example;
139
+			sourceTree = "<group>";
140
+		};
141
+		2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
142
+			isa = PBXGroup;
143
+			children = (
144
+				ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
145
+				ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
146
+				917A19FC1EBE6E8B85FE404D /* libPods-example.a */,
147
+				F9A8A9F158876EC099CFA57A /* libPods-example-tvOS.a */,
148
+				CB301596D47BBAD9E9C0A45A /* libPods-exampleTests.a */,
149
+				4830F7139A954350DD22DE4A /* libPods-example-tvOS-example-tvOSTests.a */,
150
+			);
151
+			name = Frameworks;
152
+			sourceTree = "<group>";
153
+		};
154
+		832341AE1AAA6A7D00B99B32 /* Libraries */ = {
155
+			isa = PBXGroup;
156
+			children = (
157
+			);
158
+			name = Libraries;
159
+			sourceTree = "<group>";
160
+		};
161
+		83CBB9F61A601CBA00E9B192 = {
162
+			isa = PBXGroup;
163
+			children = (
164
+				13B07FAE1A68108700A75B9A /* example */,
165
+				832341AE1AAA6A7D00B99B32 /* Libraries */,
166
+				00E356EF1AD99517003FC87E /* exampleTests */,
167
+				83CBBA001A601CBA00E9B192 /* Products */,
168
+				2D16E6871FA4F8E400B85C8A /* Frameworks */,
169
+				CCBCEDC2885B5181A2E42CE7 /* Pods */,
170
+			);
171
+			indentWidth = 2;
172
+			sourceTree = "<group>";
173
+			tabWidth = 2;
174
+			usesTabs = 0;
175
+		};
176
+		83CBBA001A601CBA00E9B192 /* Products */ = {
177
+			isa = PBXGroup;
178
+			children = (
179
+				13B07F961A680F5B00A75B9A /* example.app */,
180
+				00E356EE1AD99517003FC87E /* exampleTests.xctest */,
181
+				2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */,
182
+				2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */,
183
+			);
184
+			name = Products;
185
+			sourceTree = "<group>";
186
+		};
187
+		CCBCEDC2885B5181A2E42CE7 /* Pods */ = {
188
+			isa = PBXGroup;
189
+			children = (
190
+				4372A2FD2D749DE5C9FD8D3E /* Pods-example.debug.xcconfig */,
191
+				4FDD34C422D711AC8A7B10A7 /* Pods-example.release.xcconfig */,
192
+				775F6B7492793F5DB7ECE95B /* Pods-example-tvOS.debug.xcconfig */,
193
+				EDF80BE96CF92848F4E926EA /* Pods-example-tvOS.release.xcconfig */,
194
+				F67BC8D73DE103BA10A5488D /* Pods-example-tvOSTests.debug.xcconfig */,
195
+				59A4F27CAD1B7EFE80917453 /* Pods-example-tvOSTests.release.xcconfig */,
196
+				8A20011E75A0AD2EC5C6EAE9 /* Pods-exampleTests.debug.xcconfig */,
197
+				41B6A4553C4F552488B69B01 /* Pods-exampleTests.release.xcconfig */,
198
+				6517B8E7187010A1D58A96EE /* Pods-example-tvOS-example-tvOSTests.debug.xcconfig */,
199
+				EE3925F4209E17ECF3E692D1 /* Pods-example-tvOS-example-tvOSTests.release.xcconfig */,
200
+			);
201
+			path = Pods;
202
+			sourceTree = "<group>";
203
+		};
204
+/* End PBXGroup section */
205
+
206
+/* Begin PBXNativeTarget section */
207
+		00E356ED1AD99517003FC87E /* exampleTests */ = {
208
+			isa = PBXNativeTarget;
209
+			buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */;
210
+			buildPhases = (
211
+				A2264F1CFC0047F3C8C5D43D /* [CP] Check Pods Manifest.lock */,
212
+				00E356EA1AD99517003FC87E /* Sources */,
213
+				00E356EB1AD99517003FC87E /* Frameworks */,
214
+				00E356EC1AD99517003FC87E /* Resources */,
215
+			);
216
+			buildRules = (
217
+			);
218
+			dependencies = (
219
+				00E356F51AD99517003FC87E /* PBXTargetDependency */,
220
+			);
221
+			name = exampleTests;
222
+			productName = exampleTests;
223
+			productReference = 00E356EE1AD99517003FC87E /* exampleTests.xctest */;
224
+			productType = "com.apple.product-type.bundle.unit-test";
225
+		};
226
+		13B07F861A680F5B00A75B9A /* example */ = {
227
+			isa = PBXNativeTarget;
228
+			buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
229
+			buildPhases = (
230
+				6D39E19069EEC1F18C65E89E /* [CP] Check Pods Manifest.lock */,
231
+				FD10A7F022414F080027D42C /* Start Packager */,
232
+				13B07F871A680F5B00A75B9A /* Sources */,
233
+				13B07F8C1A680F5B00A75B9A /* Frameworks */,
234
+				13B07F8E1A680F5B00A75B9A /* Resources */,
235
+				00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
236
+			);
237
+			buildRules = (
238
+			);
239
+			dependencies = (
240
+			);
241
+			name = example;
242
+			productName = example;
243
+			productReference = 13B07F961A680F5B00A75B9A /* example.app */;
244
+			productType = "com.apple.product-type.application";
245
+		};
246
+		2D02E47A1E0B4A5D006451C7 /* example-tvOS */ = {
247
+			isa = PBXNativeTarget;
248
+			buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */;
249
+			buildPhases = (
250
+				B980633124DB020AB7EC55E3 /* [CP] Check Pods Manifest.lock */,
251
+				FD10A7F122414F3F0027D42C /* Start Packager */,
252
+				2D02E4771E0B4A5D006451C7 /* Sources */,
253
+				2D02E4781E0B4A5D006451C7 /* Frameworks */,
254
+				2D02E4791E0B4A5D006451C7 /* Resources */,
255
+				2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
256
+			);
257
+			buildRules = (
258
+			);
259
+			dependencies = (
260
+			);
261
+			name = "example-tvOS";
262
+			productName = "example-tvOS";
263
+			productReference = 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */;
264
+			productType = "com.apple.product-type.application";
265
+		};
266
+		2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */ = {
267
+			isa = PBXNativeTarget;
268
+			buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */;
269
+			buildPhases = (
270
+				56202D3091BCA37A2C594528 /* [CP] Check Pods Manifest.lock */,
271
+				2D02E48C1E0B4A5D006451C7 /* Sources */,
272
+				2D02E48D1E0B4A5D006451C7 /* Frameworks */,
273
+				2D02E48E1E0B4A5D006451C7 /* Resources */,
274
+			);
275
+			buildRules = (
276
+			);
277
+			dependencies = (
278
+				2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
279
+			);
280
+			name = "example-tvOSTests";
281
+			productName = "example-tvOSTests";
282
+			productReference = 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */;
283
+			productType = "com.apple.product-type.bundle.unit-test";
284
+		};
285
+/* End PBXNativeTarget section */
286
+
287
+/* Begin PBXProject section */
288
+		83CBB9F71A601CBA00E9B192 /* Project object */ = {
289
+			isa = PBXProject;
290
+			attributes = {
291
+				LastUpgradeCheck = 0940;
292
+				ORGANIZATIONNAME = Facebook;
293
+				TargetAttributes = {
294
+					00E356ED1AD99517003FC87E = {
295
+						CreatedOnToolsVersion = 6.2;
296
+						TestTargetID = 13B07F861A680F5B00A75B9A;
297
+					};
298
+					2D02E47A1E0B4A5D006451C7 = {
299
+						CreatedOnToolsVersion = 8.2.1;
300
+						ProvisioningStyle = Automatic;
301
+					};
302
+					2D02E48F1E0B4A5D006451C7 = {
303
+						CreatedOnToolsVersion = 8.2.1;
304
+						ProvisioningStyle = Automatic;
305
+						TestTargetID = 2D02E47A1E0B4A5D006451C7;
306
+					};
307
+				};
308
+			};
309
+			buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */;
310
+			compatibilityVersion = "Xcode 3.2";
311
+			developmentRegion = English;
312
+			hasScannedForEncodings = 0;
313
+			knownRegions = (
314
+				English,
315
+				en,
316
+				Base,
317
+			);
318
+			mainGroup = 83CBB9F61A601CBA00E9B192;
319
+			productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
320
+			projectDirPath = "";
321
+			projectRoot = "";
322
+			targets = (
323
+				13B07F861A680F5B00A75B9A /* example */,
324
+				00E356ED1AD99517003FC87E /* exampleTests */,
325
+				2D02E47A1E0B4A5D006451C7 /* example-tvOS */,
326
+				2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */,
327
+			);
328
+		};
329
+/* End PBXProject section */
330
+
331
+/* Begin PBXResourcesBuildPhase section */
332
+		00E356EC1AD99517003FC87E /* Resources */ = {
333
+			isa = PBXResourcesBuildPhase;
334
+			buildActionMask = 2147483647;
335
+			files = (
336
+			);
337
+			runOnlyForDeploymentPostprocessing = 0;
338
+		};
339
+		13B07F8E1A680F5B00A75B9A /* Resources */ = {
340
+			isa = PBXResourcesBuildPhase;
341
+			buildActionMask = 2147483647;
342
+			files = (
343
+				13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
344
+				13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
345
+			);
346
+			runOnlyForDeploymentPostprocessing = 0;
347
+		};
348
+		2D02E4791E0B4A5D006451C7 /* Resources */ = {
349
+			isa = PBXResourcesBuildPhase;
350
+			buildActionMask = 2147483647;
351
+			files = (
352
+				2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
353
+			);
354
+			runOnlyForDeploymentPostprocessing = 0;
355
+		};
356
+		2D02E48E1E0B4A5D006451C7 /* Resources */ = {
357
+			isa = PBXResourcesBuildPhase;
358
+			buildActionMask = 2147483647;
359
+			files = (
360
+			);
361
+			runOnlyForDeploymentPostprocessing = 0;
362
+		};
363
+/* End PBXResourcesBuildPhase section */
364
+
365
+/* Begin PBXShellScriptBuildPhase section */
366
+		00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
367
+			isa = PBXShellScriptBuildPhase;
368
+			buildActionMask = 2147483647;
369
+			files = (
370
+			);
371
+			inputPaths = (
372
+			);
373
+			name = "Bundle React Native code and images";
374
+			outputPaths = (
375
+			);
376
+			runOnlyForDeploymentPostprocessing = 0;
377
+			shellPath = /bin/sh;
378
+			shellScript = "export NODE_BINARY=node\n../../node_modules/react-native/scripts/react-native-xcode.sh\n";
379
+		};
380
+		2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
381
+			isa = PBXShellScriptBuildPhase;
382
+			buildActionMask = 2147483647;
383
+			files = (
384
+			);
385
+			inputPaths = (
386
+			);
387
+			name = "Bundle React Native Code And Images";
388
+			outputPaths = (
389
+			);
390
+			runOnlyForDeploymentPostprocessing = 0;
391
+			shellPath = /bin/sh;
392
+			shellScript = "export NODE_BINARY=node\n../../node_modules/react-native/scripts/react-native-xcode.sh\n";
393
+		};
394
+		56202D3091BCA37A2C594528 /* [CP] Check Pods Manifest.lock */ = {
395
+			isa = PBXShellScriptBuildPhase;
396
+			buildActionMask = 2147483647;
397
+			files = (
398
+			);
399
+			inputFileListPaths = (
400
+			);
401
+			inputPaths = (
402
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
403
+				"${PODS_ROOT}/Manifest.lock",
404
+			);
405
+			name = "[CP] Check Pods Manifest.lock";
406
+			outputFileListPaths = (
407
+			);
408
+			outputPaths = (
409
+				"$(DERIVED_FILE_DIR)/Pods-example-tvOS-example-tvOSTests-checkManifestLockResult.txt",
410
+			);
411
+			runOnlyForDeploymentPostprocessing = 0;
412
+			shellPath = /bin/sh;
413
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
414
+			showEnvVarsInLog = 0;
415
+		};
416
+		6D39E19069EEC1F18C65E89E /* [CP] Check Pods Manifest.lock */ = {
417
+			isa = PBXShellScriptBuildPhase;
418
+			buildActionMask = 2147483647;
419
+			files = (
420
+			);
421
+			inputFileListPaths = (
422
+			);
423
+			inputPaths = (
424
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
425
+				"${PODS_ROOT}/Manifest.lock",
426
+			);
427
+			name = "[CP] Check Pods Manifest.lock";
428
+			outputFileListPaths = (
429
+			);
430
+			outputPaths = (
431
+				"$(DERIVED_FILE_DIR)/Pods-example-checkManifestLockResult.txt",
432
+			);
433
+			runOnlyForDeploymentPostprocessing = 0;
434
+			shellPath = /bin/sh;
435
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
436
+			showEnvVarsInLog = 0;
437
+		};
438
+		A2264F1CFC0047F3C8C5D43D /* [CP] Check Pods Manifest.lock */ = {
439
+			isa = PBXShellScriptBuildPhase;
440
+			buildActionMask = 2147483647;
441
+			files = (
442
+			);
443
+			inputFileListPaths = (
444
+			);
445
+			inputPaths = (
446
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
447
+				"${PODS_ROOT}/Manifest.lock",
448
+			);
449
+			name = "[CP] Check Pods Manifest.lock";
450
+			outputFileListPaths = (
451
+			);
452
+			outputPaths = (
453
+				"$(DERIVED_FILE_DIR)/Pods-exampleTests-checkManifestLockResult.txt",
454
+			);
455
+			runOnlyForDeploymentPostprocessing = 0;
456
+			shellPath = /bin/sh;
457
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
458
+			showEnvVarsInLog = 0;
459
+		};
460
+		B980633124DB020AB7EC55E3 /* [CP] Check Pods Manifest.lock */ = {
461
+			isa = PBXShellScriptBuildPhase;
462
+			buildActionMask = 2147483647;
463
+			files = (
464
+			);
465
+			inputFileListPaths = (
466
+			);
467
+			inputPaths = (
468
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
469
+				"${PODS_ROOT}/Manifest.lock",
470
+			);
471
+			name = "[CP] Check Pods Manifest.lock";
472
+			outputFileListPaths = (
473
+			);
474
+			outputPaths = (
475
+				"$(DERIVED_FILE_DIR)/Pods-example-tvOS-checkManifestLockResult.txt",
476
+			);
477
+			runOnlyForDeploymentPostprocessing = 0;
478
+			shellPath = /bin/sh;
479
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
480
+			showEnvVarsInLog = 0;
481
+		};
482
+		FD10A7F022414F080027D42C /* Start Packager */ = {
483
+			isa = PBXShellScriptBuildPhase;
484
+			buildActionMask = 2147483647;
485
+			files = (
486
+			);
487
+			inputFileListPaths = (
488
+			);
489
+			inputPaths = (
490
+			);
491
+			name = "Start Packager";
492
+			outputFileListPaths = (
493
+			);
494
+			outputPaths = (
495
+			);
496
+			runOnlyForDeploymentPostprocessing = 0;
497
+			shellPath = /bin/sh;
498
+			shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n    if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n      echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n      exit 2\n    fi\n  else\n    open \"$SRCROOT/../../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n  fi\nfi\n";
499
+			showEnvVarsInLog = 0;
500
+		};
501
+		FD10A7F122414F3F0027D42C /* Start Packager */ = {
502
+			isa = PBXShellScriptBuildPhase;
503
+			buildActionMask = 2147483647;
504
+			files = (
505
+			);
506
+			inputFileListPaths = (
507
+			);
508
+			inputPaths = (
509
+			);
510
+			name = "Start Packager";
511
+			outputFileListPaths = (
512
+			);
513
+			outputPaths = (
514
+			);
515
+			runOnlyForDeploymentPostprocessing = 0;
516
+			shellPath = /bin/sh;
517
+			shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n    if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n      echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n      exit 2\n    fi\n  else\n    open \"$SRCROOT/../../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n  fi\nfi\n";
518
+			showEnvVarsInLog = 0;
519
+		};
520
+/* End PBXShellScriptBuildPhase section */
521
+
522
+/* Begin PBXSourcesBuildPhase section */
523
+		00E356EA1AD99517003FC87E /* Sources */ = {
524
+			isa = PBXSourcesBuildPhase;
525
+			buildActionMask = 2147483647;
526
+			files = (
527
+				00E356F31AD99517003FC87E /* exampleTests.m in Sources */,
528
+			);
529
+			runOnlyForDeploymentPostprocessing = 0;
530
+		};
531
+		13B07F871A680F5B00A75B9A /* Sources */ = {
532
+			isa = PBXSourcesBuildPhase;
533
+			buildActionMask = 2147483647;
534
+			files = (
535
+				13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
536
+				13B07FC11A68108700A75B9A /* main.m in Sources */,
537
+			);
538
+			runOnlyForDeploymentPostprocessing = 0;
539
+		};
540
+		2D02E4771E0B4A5D006451C7 /* Sources */ = {
541
+			isa = PBXSourcesBuildPhase;
542
+			buildActionMask = 2147483647;
543
+			files = (
544
+				2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
545
+				2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
546
+			);
547
+			runOnlyForDeploymentPostprocessing = 0;
548
+		};
549
+		2D02E48C1E0B4A5D006451C7 /* Sources */ = {
550
+			isa = PBXSourcesBuildPhase;
551
+			buildActionMask = 2147483647;
552
+			files = (
553
+				2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */,
554
+			);
555
+			runOnlyForDeploymentPostprocessing = 0;
556
+		};
557
+/* End PBXSourcesBuildPhase section */
558
+
559
+/* Begin PBXTargetDependency section */
560
+		00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
561
+			isa = PBXTargetDependency;
562
+			target = 13B07F861A680F5B00A75B9A /* example */;
563
+			targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
564
+		};
565
+		2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
566
+			isa = PBXTargetDependency;
567
+			target = 2D02E47A1E0B4A5D006451C7 /* example-tvOS */;
568
+			targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
569
+		};
570
+/* End PBXTargetDependency section */
571
+
572
+/* Begin PBXVariantGroup section */
573
+		13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
574
+			isa = PBXVariantGroup;
575
+			children = (
576
+				13B07FB21A68108700A75B9A /* Base */,
577
+			);
578
+			name = LaunchScreen.xib;
579
+			path = example;
580
+			sourceTree = "<group>";
581
+		};
582
+/* End PBXVariantGroup section */
583
+
584
+/* Begin XCBuildConfiguration section */
585
+		00E356F61AD99517003FC87E /* Debug */ = {
586
+			isa = XCBuildConfiguration;
587
+			baseConfigurationReference = 8A20011E75A0AD2EC5C6EAE9 /* Pods-exampleTests.debug.xcconfig */;
588
+			buildSettings = {
589
+				BUNDLE_LOADER = "$(TEST_HOST)";
590
+				GCC_PREPROCESSOR_DEFINITIONS = (
591
+					"DEBUG=1",
592
+					"$(inherited)",
593
+				);
594
+				INFOPLIST_FILE = exampleTests/Info.plist;
595
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
596
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
597
+				OTHER_LDFLAGS = (
598
+					"-ObjC",
599
+					"-lc++",
600
+					"$(inherited)",
601
+				);
602
+				PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
603
+				PRODUCT_NAME = "$(TARGET_NAME)";
604
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
605
+			};
606
+			name = Debug;
607
+		};
608
+		00E356F71AD99517003FC87E /* Release */ = {
609
+			isa = XCBuildConfiguration;
610
+			baseConfigurationReference = 41B6A4553C4F552488B69B01 /* Pods-exampleTests.release.xcconfig */;
611
+			buildSettings = {
612
+				BUNDLE_LOADER = "$(TEST_HOST)";
613
+				COPY_PHASE_STRIP = NO;
614
+				INFOPLIST_FILE = exampleTests/Info.plist;
615
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
616
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
617
+				OTHER_LDFLAGS = (
618
+					"-ObjC",
619
+					"-lc++",
620
+					"$(inherited)",
621
+				);
622
+				PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
623
+				PRODUCT_NAME = "$(TARGET_NAME)";
624
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
625
+			};
626
+			name = Release;
627
+		};
628
+		13B07F941A680F5B00A75B9A /* Debug */ = {
629
+			isa = XCBuildConfiguration;
630
+			baseConfigurationReference = 4372A2FD2D749DE5C9FD8D3E /* Pods-example.debug.xcconfig */;
631
+			buildSettings = {
632
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
633
+				CURRENT_PROJECT_VERSION = 1;
634
+				DEAD_CODE_STRIPPING = NO;
635
+				INFOPLIST_FILE = example/Info.plist;
636
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
637
+				OTHER_LDFLAGS = (
638
+					"$(inherited)",
639
+					"-ObjC",
640
+					"-lc++",
641
+				);
642
+				PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
643
+				PRODUCT_NAME = example;
644
+				VERSIONING_SYSTEM = "apple-generic";
645
+			};
646
+			name = Debug;
647
+		};
648
+		13B07F951A680F5B00A75B9A /* Release */ = {
649
+			isa = XCBuildConfiguration;
650
+			baseConfigurationReference = 4FDD34C422D711AC8A7B10A7 /* Pods-example.release.xcconfig */;
651
+			buildSettings = {
652
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
653
+				CURRENT_PROJECT_VERSION = 1;
654
+				INFOPLIST_FILE = example/Info.plist;
655
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
656
+				OTHER_LDFLAGS = (
657
+					"$(inherited)",
658
+					"-ObjC",
659
+					"-lc++",
660
+				);
661
+				PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
662
+				PRODUCT_NAME = example;
663
+				VERSIONING_SYSTEM = "apple-generic";
664
+			};
665
+			name = Release;
666
+		};
667
+		2D02E4971E0B4A5E006451C7 /* Debug */ = {
668
+			isa = XCBuildConfiguration;
669
+			baseConfigurationReference = 775F6B7492793F5DB7ECE95B /* Pods-example-tvOS.debug.xcconfig */;
670
+			buildSettings = {
671
+				ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
672
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
673
+				CLANG_ANALYZER_NONNULL = YES;
674
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
675
+				CLANG_WARN_INFINITE_RECURSION = YES;
676
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
677
+				DEBUG_INFORMATION_FORMAT = dwarf;
678
+				ENABLE_TESTABILITY = YES;
679
+				GCC_NO_COMMON_BLOCKS = YES;
680
+				INFOPLIST_FILE = "example-tvOS/Info.plist";
681
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
682
+				OTHER_LDFLAGS = (
683
+					"$(inherited)",
684
+					"-ObjC",
685
+					"-lc++",
686
+				);
687
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS";
688
+				PRODUCT_NAME = "$(TARGET_NAME)";
689
+				SDKROOT = appletvos;
690
+				TARGETED_DEVICE_FAMILY = 3;
691
+				TVOS_DEPLOYMENT_TARGET = 9.2;
692
+			};
693
+			name = Debug;
694
+		};
695
+		2D02E4981E0B4A5E006451C7 /* Release */ = {
696
+			isa = XCBuildConfiguration;
697
+			baseConfigurationReference = EDF80BE96CF92848F4E926EA /* Pods-example-tvOS.release.xcconfig */;
698
+			buildSettings = {
699
+				ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
700
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
701
+				CLANG_ANALYZER_NONNULL = YES;
702
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
703
+				CLANG_WARN_INFINITE_RECURSION = YES;
704
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
705
+				COPY_PHASE_STRIP = NO;
706
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
707
+				GCC_NO_COMMON_BLOCKS = YES;
708
+				INFOPLIST_FILE = "example-tvOS/Info.plist";
709
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
710
+				OTHER_LDFLAGS = (
711
+					"$(inherited)",
712
+					"-ObjC",
713
+					"-lc++",
714
+				);
715
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS";
716
+				PRODUCT_NAME = "$(TARGET_NAME)";
717
+				SDKROOT = appletvos;
718
+				TARGETED_DEVICE_FAMILY = 3;
719
+				TVOS_DEPLOYMENT_TARGET = 9.2;
720
+			};
721
+			name = Release;
722
+		};
723
+		2D02E4991E0B4A5E006451C7 /* Debug */ = {
724
+			isa = XCBuildConfiguration;
725
+			baseConfigurationReference = 6517B8E7187010A1D58A96EE /* Pods-example-tvOS-example-tvOSTests.debug.xcconfig */;
726
+			buildSettings = {
727
+				BUNDLE_LOADER = "$(TEST_HOST)";
728
+				CLANG_ANALYZER_NONNULL = YES;
729
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
730
+				CLANG_WARN_INFINITE_RECURSION = YES;
731
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
732
+				DEBUG_INFORMATION_FORMAT = dwarf;
733
+				ENABLE_TESTABILITY = YES;
734
+				GCC_NO_COMMON_BLOCKS = YES;
735
+				INFOPLIST_FILE = "example-tvOSTests/Info.plist";
736
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
737
+				OTHER_LDFLAGS = (
738
+					"$(inherited)",
739
+					"-ObjC",
740
+					"-lc++",
741
+				);
742
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests";
743
+				PRODUCT_NAME = "$(TARGET_NAME)";
744
+				SDKROOT = appletvos;
745
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS";
746
+				TVOS_DEPLOYMENT_TARGET = 10.1;
747
+			};
748
+			name = Debug;
749
+		};
750
+		2D02E49A1E0B4A5E006451C7 /* Release */ = {
751
+			isa = XCBuildConfiguration;
752
+			baseConfigurationReference = EE3925F4209E17ECF3E692D1 /* Pods-example-tvOS-example-tvOSTests.release.xcconfig */;
753
+			buildSettings = {
754
+				BUNDLE_LOADER = "$(TEST_HOST)";
755
+				CLANG_ANALYZER_NONNULL = YES;
756
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
757
+				CLANG_WARN_INFINITE_RECURSION = YES;
758
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
759
+				COPY_PHASE_STRIP = NO;
760
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
761
+				GCC_NO_COMMON_BLOCKS = YES;
762
+				INFOPLIST_FILE = "example-tvOSTests/Info.plist";
763
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
764
+				OTHER_LDFLAGS = (
765
+					"$(inherited)",
766
+					"-ObjC",
767
+					"-lc++",
768
+				);
769
+				PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests";
770
+				PRODUCT_NAME = "$(TARGET_NAME)";
771
+				SDKROOT = appletvos;
772
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS";
773
+				TVOS_DEPLOYMENT_TARGET = 10.1;
774
+			};
775
+			name = Release;
776
+		};
777
+		83CBBA201A601CBA00E9B192 /* Debug */ = {
778
+			isa = XCBuildConfiguration;
779
+			buildSettings = {
780
+				ALWAYS_SEARCH_USER_PATHS = NO;
781
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
782
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
783
+				CLANG_CXX_LIBRARY = "libc++";
784
+				CLANG_ENABLE_MODULES = YES;
785
+				CLANG_ENABLE_OBJC_ARC = YES;
786
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
787
+				CLANG_WARN_BOOL_CONVERSION = YES;
788
+				CLANG_WARN_COMMA = YES;
789
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
790
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
791
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
792
+				CLANG_WARN_EMPTY_BODY = YES;
793
+				CLANG_WARN_ENUM_CONVERSION = YES;
794
+				CLANG_WARN_INFINITE_RECURSION = YES;
795
+				CLANG_WARN_INT_CONVERSION = YES;
796
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
797
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
798
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
799
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
800
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
801
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
802
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
803
+				CLANG_WARN_UNREACHABLE_CODE = YES;
804
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
805
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
806
+				COPY_PHASE_STRIP = NO;
807
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
808
+				ENABLE_TESTABILITY = YES;
809
+				GCC_C_LANGUAGE_STANDARD = gnu99;
810
+				GCC_DYNAMIC_NO_PIC = NO;
811
+				GCC_NO_COMMON_BLOCKS = YES;
812
+				GCC_OPTIMIZATION_LEVEL = 0;
813
+				GCC_PREPROCESSOR_DEFINITIONS = (
814
+					"DEBUG=1",
815
+					"$(inherited)",
816
+				);
817
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
818
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
819
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
820
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
821
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
822
+				GCC_WARN_UNUSED_FUNCTION = YES;
823
+				GCC_WARN_UNUSED_VARIABLE = YES;
824
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
825
+				MTL_ENABLE_DEBUG_INFO = YES;
826
+				ONLY_ACTIVE_ARCH = YES;
827
+				SDKROOT = iphoneos;
828
+			};
829
+			name = Debug;
830
+		};
831
+		83CBBA211A601CBA00E9B192 /* Release */ = {
832
+			isa = XCBuildConfiguration;
833
+			buildSettings = {
834
+				ALWAYS_SEARCH_USER_PATHS = NO;
835
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
836
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
837
+				CLANG_CXX_LIBRARY = "libc++";
838
+				CLANG_ENABLE_MODULES = YES;
839
+				CLANG_ENABLE_OBJC_ARC = YES;
840
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
841
+				CLANG_WARN_BOOL_CONVERSION = YES;
842
+				CLANG_WARN_COMMA = YES;
843
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
844
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
845
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
846
+				CLANG_WARN_EMPTY_BODY = YES;
847
+				CLANG_WARN_ENUM_CONVERSION = YES;
848
+				CLANG_WARN_INFINITE_RECURSION = YES;
849
+				CLANG_WARN_INT_CONVERSION = YES;
850
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
851
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
852
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
853
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
854
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
855
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
856
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
857
+				CLANG_WARN_UNREACHABLE_CODE = YES;
858
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
859
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
860
+				COPY_PHASE_STRIP = YES;
861
+				ENABLE_NS_ASSERTIONS = NO;
862
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
863
+				GCC_C_LANGUAGE_STANDARD = gnu99;
864
+				GCC_NO_COMMON_BLOCKS = YES;
865
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
866
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
867
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
868
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
869
+				GCC_WARN_UNUSED_FUNCTION = YES;
870
+				GCC_WARN_UNUSED_VARIABLE = YES;
871
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
872
+				MTL_ENABLE_DEBUG_INFO = NO;
873
+				SDKROOT = iphoneos;
874
+				VALIDATE_PRODUCT = YES;
875
+			};
876
+			name = Release;
877
+		};
878
+/* End XCBuildConfiguration section */
879
+
880
+/* Begin XCConfigurationList section */
881
+		00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */ = {
882
+			isa = XCConfigurationList;
883
+			buildConfigurations = (
884
+				00E356F61AD99517003FC87E /* Debug */,
885
+				00E356F71AD99517003FC87E /* Release */,
886
+			);
887
+			defaultConfigurationIsVisible = 0;
888
+			defaultConfigurationName = Release;
889
+		};
890
+		13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */ = {
891
+			isa = XCConfigurationList;
892
+			buildConfigurations = (
893
+				13B07F941A680F5B00A75B9A /* Debug */,
894
+				13B07F951A680F5B00A75B9A /* Release */,
895
+			);
896
+			defaultConfigurationIsVisible = 0;
897
+			defaultConfigurationName = Release;
898
+		};
899
+		2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */ = {
900
+			isa = XCConfigurationList;
901
+			buildConfigurations = (
902
+				2D02E4971E0B4A5E006451C7 /* Debug */,
903
+				2D02E4981E0B4A5E006451C7 /* Release */,
904
+			);
905
+			defaultConfigurationIsVisible = 0;
906
+			defaultConfigurationName = Release;
907
+		};
908
+		2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */ = {
909
+			isa = XCConfigurationList;
910
+			buildConfigurations = (
911
+				2D02E4991E0B4A5E006451C7 /* Debug */,
912
+				2D02E49A1E0B4A5E006451C7 /* Release */,
913
+			);
914
+			defaultConfigurationIsVisible = 0;
915
+			defaultConfigurationName = Release;
916
+		};
917
+		83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = {
918
+			isa = XCConfigurationList;
919
+			buildConfigurations = (
920
+				83CBBA201A601CBA00E9B192 /* Debug */,
921
+				83CBBA211A601CBA00E9B192 /* Release */,
922
+			);
923
+			defaultConfigurationIsVisible = 0;
924
+			defaultConfigurationName = Release;
925
+		};
926
+/* End XCConfigurationList section */
927
+	};
928
+	rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
929
+}

+ 88
- 0
example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Scheme
3
+   LastUpgradeVersion = "1130"
4
+   version = "1.3">
5
+   <BuildAction
6
+      parallelizeBuildables = "YES"
7
+      buildImplicitDependencies = "YES">
8
+      <BuildActionEntries>
9
+         <BuildActionEntry
10
+            buildForTesting = "YES"
11
+            buildForRunning = "YES"
12
+            buildForProfiling = "YES"
13
+            buildForArchiving = "YES"
14
+            buildForAnalyzing = "YES">
15
+            <BuildableReference
16
+               BuildableIdentifier = "primary"
17
+               BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
18
+               BuildableName = "example-tvOS.app"
19
+               BlueprintName = "example-tvOS"
20
+               ReferencedContainer = "container:example.xcodeproj">
21
+            </BuildableReference>
22
+         </BuildActionEntry>
23
+      </BuildActionEntries>
24
+   </BuildAction>
25
+   <TestAction
26
+      buildConfiguration = "Debug"
27
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+      shouldUseLaunchSchemeArgsEnv = "YES">
30
+      <Testables>
31
+         <TestableReference
32
+            skipped = "NO">
33
+            <BuildableReference
34
+               BuildableIdentifier = "primary"
35
+               BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
36
+               BuildableName = "example-tvOSTests.xctest"
37
+               BlueprintName = "example-tvOSTests"
38
+               ReferencedContainer = "container:example.xcodeproj">
39
+            </BuildableReference>
40
+         </TestableReference>
41
+      </Testables>
42
+   </TestAction>
43
+   <LaunchAction
44
+      buildConfiguration = "Debug"
45
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
46
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
47
+      launchStyle = "0"
48
+      useCustomWorkingDirectory = "NO"
49
+      ignoresPersistentStateOnLaunch = "NO"
50
+      debugDocumentVersioning = "YES"
51
+      debugServiceExtension = "internal"
52
+      allowLocationSimulation = "YES">
53
+      <BuildableProductRunnable
54
+         runnableDebuggingMode = "0">
55
+         <BuildableReference
56
+            BuildableIdentifier = "primary"
57
+            BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
58
+            BuildableName = "example-tvOS.app"
59
+            BlueprintName = "example-tvOS"
60
+            ReferencedContainer = "container:example.xcodeproj">
61
+         </BuildableReference>
62
+      </BuildableProductRunnable>
63
+   </LaunchAction>
64
+   <ProfileAction
65
+      buildConfiguration = "Release"
66
+      shouldUseLaunchSchemeArgsEnv = "YES"
67
+      savedToolIdentifier = ""
68
+      useCustomWorkingDirectory = "NO"
69
+      debugDocumentVersioning = "YES">
70
+      <BuildableProductRunnable
71
+         runnableDebuggingMode = "0">
72
+         <BuildableReference
73
+            BuildableIdentifier = "primary"
74
+            BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
75
+            BuildableName = "example-tvOS.app"
76
+            BlueprintName = "example-tvOS"
77
+            ReferencedContainer = "container:example.xcodeproj">
78
+         </BuildableReference>
79
+      </BuildableProductRunnable>
80
+   </ProfileAction>
81
+   <AnalyzeAction
82
+      buildConfiguration = "Debug">
83
+   </AnalyzeAction>
84
+   <ArchiveAction
85
+      buildConfiguration = "Release"
86
+      revealArchiveInOrganizer = "YES">
87
+   </ArchiveAction>
88
+</Scheme>

+ 88
- 0
example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Scheme
3
+   LastUpgradeVersion = "1130"
4
+   version = "1.3">
5
+   <BuildAction
6
+      parallelizeBuildables = "YES"
7
+      buildImplicitDependencies = "YES">
8
+      <BuildActionEntries>
9
+         <BuildActionEntry
10
+            buildForTesting = "YES"
11
+            buildForRunning = "YES"
12
+            buildForProfiling = "YES"
13
+            buildForArchiving = "YES"
14
+            buildForAnalyzing = "YES">
15
+            <BuildableReference
16
+               BuildableIdentifier = "primary"
17
+               BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
18
+               BuildableName = "example.app"
19
+               BlueprintName = "example"
20
+               ReferencedContainer = "container:example.xcodeproj">
21
+            </BuildableReference>
22
+         </BuildActionEntry>
23
+      </BuildActionEntries>
24
+   </BuildAction>
25
+   <TestAction
26
+      buildConfiguration = "Debug"
27
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+      shouldUseLaunchSchemeArgsEnv = "YES">
30
+      <Testables>
31
+         <TestableReference
32
+            skipped = "NO">
33
+            <BuildableReference
34
+               BuildableIdentifier = "primary"
35
+               BlueprintIdentifier = "00E356ED1AD99517003FC87E"
36
+               BuildableName = "exampleTests.xctest"
37
+               BlueprintName = "exampleTests"
38
+               ReferencedContainer = "container:example.xcodeproj">
39
+            </BuildableReference>
40
+         </TestableReference>
41
+      </Testables>
42
+   </TestAction>
43
+   <LaunchAction
44
+      buildConfiguration = "Debug"
45
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
46
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
47
+      launchStyle = "0"
48
+      useCustomWorkingDirectory = "NO"
49
+      ignoresPersistentStateOnLaunch = "NO"
50
+      debugDocumentVersioning = "YES"
51
+      debugServiceExtension = "internal"
52
+      allowLocationSimulation = "YES">
53
+      <BuildableProductRunnable
54
+         runnableDebuggingMode = "0">
55
+         <BuildableReference
56
+            BuildableIdentifier = "primary"
57
+            BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
58
+            BuildableName = "example.app"
59
+            BlueprintName = "example"
60
+            ReferencedContainer = "container:example.xcodeproj">
61
+         </BuildableReference>
62
+      </BuildableProductRunnable>
63
+   </LaunchAction>
64
+   <ProfileAction
65
+      buildConfiguration = "Release"
66
+      shouldUseLaunchSchemeArgsEnv = "YES"
67
+      savedToolIdentifier = ""
68
+      useCustomWorkingDirectory = "NO"
69
+      debugDocumentVersioning = "YES">
70
+      <BuildableProductRunnable
71
+         runnableDebuggingMode = "0">
72
+         <BuildableReference
73
+            BuildableIdentifier = "primary"
74
+            BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
75
+            BuildableName = "example.app"
76
+            BlueprintName = "example"
77
+            ReferencedContainer = "container:example.xcodeproj">
78
+         </BuildableReference>
79
+      </BuildableProductRunnable>
80
+   </ProfileAction>
81
+   <AnalyzeAction
82
+      buildConfiguration = "Debug">
83
+   </AnalyzeAction>
84
+   <ArchiveAction
85
+      buildConfiguration = "Release"
86
+      revealArchiveInOrganizer = "YES">
87
+   </ArchiveAction>
88
+</Scheme>

+ 10
- 0
example/ios/example.xcworkspace/contents.xcworkspacedata View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Workspace
3
+   version = "1.0">
4
+   <FileRef
5
+      location = "group:example.xcodeproj">
6
+   </FileRef>
7
+   <FileRef
8
+      location = "group:Pods/Pods.xcodeproj">
9
+   </FileRef>
10
+</Workspace>

+ 8
- 0
example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>IDEDidComputeMac32BitWarning</key>
6
+	<true/>
7
+</dict>
8
+</plist>

+ 15
- 0
example/ios/example/AppDelegate.h View File

1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+#import <React/RCTBridgeDelegate.h>
9
+#import <UIKit/UIKit.h>
10
+
11
+@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
12
+
13
+@property (nonatomic, strong) UIWindow *window;
14
+
15
+@end

+ 42
- 0
example/ios/example/AppDelegate.m View File

1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+#import "AppDelegate.h"
9
+
10
+#import <React/RCTBridge.h>
11
+#import <React/RCTBundleURLProvider.h>
12
+#import <React/RCTRootView.h>
13
+
14
+@implementation AppDelegate
15
+
16
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17
+{
18
+  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
19
+  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
20
+                                                   moduleName:@"example"
21
+                                            initialProperties:nil];
22
+
23
+  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
24
+
25
+  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
26
+  UIViewController *rootViewController = [UIViewController new];
27
+  rootViewController.view = rootView;
28
+  self.window.rootViewController = rootViewController;
29
+  [self.window makeKeyAndVisible];
30
+  return YES;
31
+}
32
+
33
+- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
34
+{
35
+#if DEBUG
36
+  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"example/index" fallbackResource:nil];
37
+#else
38
+  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
39
+#endif
40
+}
41
+
42
+@end

+ 42
- 0
example/ios/example/Base.lproj/LaunchScreen.xib View File

1
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
3
+    <dependencies>
4
+        <deployment identifier="iOS"/>
5
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
6
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
7
+    </dependencies>
8
+    <objects>
9
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
10
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
11
+        <view contentMode="scaleToFill" id="iN0-l3-epB">
12
+            <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
13
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
14
+            <subviews>
15
+                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
16
+                    <rect key="frame" x="20" y="439" width="441" height="21"/>
17
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
18
+                    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
19
+                    <nil key="highlightedColor"/>
20
+                </label>
21
+                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="example" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
22
+                    <rect key="frame" x="20" y="140" width="441" height="43"/>
23
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
24
+                    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
25
+                    <nil key="highlightedColor"/>
26
+                </label>
27
+            </subviews>
28
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
29
+            <constraints>
30
+                <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
31
+                <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
32
+                <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
33
+                <constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
34
+                <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
35
+                <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
36
+            </constraints>
37
+            <nil key="simulatedStatusBarMetrics"/>
38
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
39
+            <point key="canvasLocation" x="548" y="455"/>
40
+        </view>
41
+    </objects>
42
+</document>

+ 38
- 0
example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json View File

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
+}

+ 6
- 0
example/ios/example/Images.xcassets/Contents.json View File

1
+{
2
+  "info" : {
3
+    "version" : 1,
4
+    "author" : "xcode"
5
+  }
6
+}

+ 57
- 0
example/ios/example/Info.plist View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleDisplayName</key>
8
+	<string>example</string>
9
+	<key>CFBundleExecutable</key>
10
+	<string>$(EXECUTABLE_NAME)</string>
11
+	<key>CFBundleIdentifier</key>
12
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+	<key>CFBundleInfoDictionaryVersion</key>
14
+	<string>6.0</string>
15
+	<key>CFBundleName</key>
16
+	<string>$(PRODUCT_NAME)</string>
17
+	<key>CFBundlePackageType</key>
18
+	<string>APPL</string>
19
+	<key>CFBundleShortVersionString</key>
20
+	<string>1.0</string>
21
+	<key>CFBundleSignature</key>
22
+	<string>????</string>
23
+	<key>CFBundleVersion</key>
24
+	<string>1</string>
25
+	<key>LSRequiresIPhoneOS</key>
26
+	<true/>
27
+	<key>NSAppTransportSecurity</key>
28
+	<dict>
29
+		<key>NSAllowsArbitraryLoads</key>
30
+		<true/>
31
+		<key>NSExceptionDomains</key>
32
+		<dict>
33
+			<key>localhost</key>
34
+			<dict>
35
+				<key>NSExceptionAllowsInsecureHTTPLoads</key>
36
+				<true/>
37
+			</dict>
38
+		</dict>
39
+	</dict>
40
+	<key>NSLocationWhenInUseUsageDescription</key>
41
+	<string></string>
42
+	<key>UILaunchStoryboardName</key>
43
+	<string>LaunchScreen</string>
44
+	<key>UIRequiredDeviceCapabilities</key>
45
+	<array>
46
+		<string>armv7</string>
47
+	</array>
48
+	<key>UISupportedInterfaceOrientations</key>
49
+	<array>
50
+		<string>UIInterfaceOrientationPortrait</string>
51
+		<string>UIInterfaceOrientationLandscapeLeft</string>
52
+		<string>UIInterfaceOrientationLandscapeRight</string>
53
+	</array>
54
+	<key>UIViewControllerBasedStatusBarAppearance</key>
55
+	<false/>
56
+</dict>
57
+</plist>

+ 16
- 0
example/ios/example/main.m View File

1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+#import <UIKit/UIKit.h>
9
+
10
+#import "AppDelegate.h"
11
+
12
+int main(int argc, char * argv[]) {
13
+  @autoreleasepool {
14
+    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15
+  }
16
+}

+ 24
- 0
example/ios/exampleTests/Info.plist View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleExecutable</key>
8
+	<string>$(EXECUTABLE_NAME)</string>
9
+	<key>CFBundleIdentifier</key>
10
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+	<key>CFBundleInfoDictionaryVersion</key>
12
+	<string>6.0</string>
13
+	<key>CFBundleName</key>
14
+	<string>$(PRODUCT_NAME)</string>
15
+	<key>CFBundlePackageType</key>
16
+	<string>BNDL</string>
17
+	<key>CFBundleShortVersionString</key>
18
+	<string>1.0</string>
19
+	<key>CFBundleSignature</key>
20
+	<string>????</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+</dict>
24
+</plist>

+ 72
- 0
example/ios/exampleTests/exampleTests.m View File

1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+#import <UIKit/UIKit.h>
9
+#import <XCTest/XCTest.h>
10
+
11
+#import <React/RCTLog.h>
12
+#import <React/RCTRootView.h>
13
+
14
+#define TIMEOUT_SECONDS 600
15
+#define TEXT_TO_LOOK_FOR @"Welcome to React"
16
+
17
+@interface exampleTests : XCTestCase
18
+
19
+@end
20
+
21
+@implementation exampleTests
22
+
23
+- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
24
+{
25
+  if (test(view)) {
26
+    return YES;
27
+  }
28
+  for (UIView *subview in [view subviews]) {
29
+    if ([self findSubviewInView:subview matching:test]) {
30
+      return YES;
31
+    }
32
+  }
33
+  return NO;
34
+}
35
+
36
+- (void)testRendersWelcomeScreen
37
+{
38
+  UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
39
+  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
40
+  BOOL foundElement = NO;
41
+
42
+  __block NSString *redboxError = nil;
43
+#ifdef DEBUG
44
+  RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
45
+    if (level >= RCTLogLevelError) {
46
+      redboxError = message;
47
+    }
48
+  });
49
+#endif
50
+
51
+  while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52
+    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53
+    [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54
+
55
+    foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56
+      if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57
+        return YES;
58
+      }
59
+      return NO;
60
+    }];
61
+  }
62
+  
63
+#ifdef DEBUG
64
+  RCTSetLogFunction(RCTDefaultLogFunction);
65
+#endif
66
+
67
+  XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
68
+  XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
69
+}
70
+
71
+
72
+@end

+ 42
- 0
example/macos/Podfile View File

1
+require_relative '../../node_modules/@react-native-community/cli-platform-ios/native_modules'
2
+
3
+abstract_target 'Shared' do
4
+  use_native_modules!
5
+
6
+  pod 'react-native-webview', :path => "../.."
7
+
8
+  pod 'React', :path => "../../node_modules/react-native-macos/"
9
+  pod 'React-Core', :path => "../../node_modules/react-native-macos/React"
10
+  pod 'React-fishhook', :path => "../../node_modules/react-native-macos/Libraries/fishhook"
11
+  pod 'React-RCTActionSheet', :path => "../../node_modules/react-native-macos/Libraries/ActionSheetIOS"
12
+  pod 'React-RCTAnimation', :path => "../../node_modules/react-native-macos/Libraries/NativeAnimation"
13
+  pod 'React-RCTBlob', :path => "../../node_modules/react-native-macos/Libraries/Blob"
14
+  pod 'React-RCTImage', :path => "../../node_modules/react-native-macos/Libraries/Image"
15
+  pod 'React-RCTLinking', :path => "../../node_modules/react-native-macos/Libraries/LinkingIOS"
16
+  pod 'React-RCTNetwork', :path => "../../node_modules/react-native-macos/Libraries/Network"
17
+  pod 'React-RCTSettings', :path => "../../node_modules/react-native-macos/Libraries/Settings"
18
+  pod 'React-RCTText', :path => "../../node_modules/react-native-macos/Libraries/Text"
19
+  pod 'React-RCTVibration', :path => "../../node_modules/react-native-macos/Libraries/Vibration"
20
+  pod 'React-RCTWebSocket', :path => "../../node_modules/react-native-macos/Libraries/WebSocket"
21
+  pod 'React-cxxreact', :path => "../../node_modules/react-native-macos/ReactCommon/cxxreact"
22
+  pod 'React-jscallinvoker', :path => "../../node_modules/react-native-macos/ReactCommon/jscallinvoker"
23
+  pod 'React-jsi', :path => "../../node_modules/react-native-macos/ReactCommon/jsi"
24
+  pod 'React-jsiexecutor', :path => "../../node_modules/react-native-macos/ReactCommon/jsiexecutor"
25
+  pod 'React-jsinspector', :path => "../../node_modules/react-native-macos/ReactCommon/jsinspector"
26
+  pod 'yoga', :path => "../../node_modules/react-native-macos/ReactCommon/yoga"
27
+  pod 'DoubleConversion', :podspec => "../../node_modules/react-native-macos/third-party-podspecs/DoubleConversion.podspec"
28
+  pod 'glog', :podspec => "../../node_modules/react-native-macos/third-party-podspecs/glog.podspec"
29
+  pod 'Folly', :podspec => "../../node_modules/react-native-macos/third-party-podspecs/Folly.podspec"
30
+  pod 'boost-for-react-native', :podspec => "../../node_modules/react-native-macos/third-party-podspecs/boost-for-react-native.podspec"
31
+  pod 'React-DevSupport', :path => "../../node_modules/react-native-macos/React"
32
+
33
+  target 'example-macOS' do
34
+    platform :macos, '10.14'
35
+    # Pods specifically for macOS target
36
+  end
37
+
38
+  target 'example-iOS' do
39
+    platform :ios, '9'
40
+    # Pods specifically for iOS target
41
+  end
42
+end

+ 199
- 0
example/macos/Podfile.lock View File

1
+PODS:
2
+  - boost-for-react-native (1.63.0)
3
+  - DoubleConversion (1.1.6)
4
+  - Folly (2018.10.22.00):
5
+    - boost-for-react-native
6
+    - DoubleConversion
7
+    - Folly/Default (= 2018.10.22.00)
8
+    - glog
9
+  - Folly/Default (2018.10.22.00):
10
+    - boost-for-react-native
11
+    - DoubleConversion
12
+    - glog
13
+  - glog (0.3.5)
14
+  - React (0.60.0-microsoft.73):
15
+    - React-Core (= 0.60.0-microsoft.73)
16
+    - React-DevSupport (= 0.60.0-microsoft.73)
17
+    - React-RCTActionSheet (= 0.60.0-microsoft.73)
18
+    - React-RCTAnimation (= 0.60.0-microsoft.73)
19
+    - React-RCTBlob (= 0.60.0-microsoft.73)
20
+    - React-RCTImage (= 0.60.0-microsoft.73)
21
+    - React-RCTLinking (= 0.60.0-microsoft.73)
22
+    - React-RCTNetwork (= 0.60.0-microsoft.73)
23
+    - React-RCTSettings (= 0.60.0-microsoft.73)
24
+    - React-RCTText (= 0.60.0-microsoft.73)
25
+    - React-RCTVibration (= 0.60.0-microsoft.73)
26
+    - React-RCTWebSocket (= 0.60.0-microsoft.73)
27
+  - React-Core (0.60.0-microsoft.73):
28
+    - Folly (= 2018.10.22.00)
29
+    - React-cxxreact (= 0.60.0-microsoft.73)
30
+    - React-jsiexecutor (= 0.60.0-microsoft.73)
31
+    - yoga (= 0.60.0-microsoft.73.React)
32
+  - React-cxxreact (0.60.0-microsoft.73):
33
+    - boost-for-react-native (= 1.63.0)
34
+    - DoubleConversion
35
+    - Folly (= 2018.10.22.00)
36
+    - glog
37
+    - React-jsinspector (= 0.60.0-microsoft.73)
38
+  - React-DevSupport (0.60.0-microsoft.73):
39
+    - React-Core (= 0.60.0-microsoft.73)
40
+    - React-RCTWebSocket (= 0.60.0-microsoft.73)
41
+  - React-fishhook (0.60.0-microsoft.73)
42
+  - React-jscallinvoker (0.60.0-microsoft.73):
43
+    - Folly (= 2018.10.22.00)
44
+    - React-cxxreact (= 0.60.0-microsoft.73)
45
+  - React-jsi (0.60.0-microsoft.73):
46
+    - boost-for-react-native (= 1.63.0)
47
+    - DoubleConversion
48
+    - Folly (= 2018.10.22.00)
49
+    - glog
50
+    - React-jsi/Default (= 0.60.0-microsoft.73)
51
+  - React-jsi/Default (0.60.0-microsoft.73):
52
+    - boost-for-react-native (= 1.63.0)
53
+    - DoubleConversion
54
+    - Folly (= 2018.10.22.00)
55
+    - glog
56
+  - React-jsiexecutor (0.60.0-microsoft.73):
57
+    - DoubleConversion
58
+    - Folly (= 2018.10.22.00)
59
+    - glog
60
+    - React-cxxreact (= 0.60.0-microsoft.73)
61
+    - React-jsi (= 0.60.0-microsoft.73)
62
+  - React-jsinspector (0.60.0-microsoft.73)
63
+  - react-native-webview (9.2.1):
64
+    - React
65
+  - React-RCTActionSheet (0.60.0-microsoft.73):
66
+    - React-Core (= 0.60.0-microsoft.73)
67
+  - React-RCTAnimation (0.60.0-microsoft.73):
68
+    - React-Core (= 0.60.0-microsoft.73)
69
+  - React-RCTBlob (0.60.0-microsoft.73):
70
+    - React-Core (= 0.60.0-microsoft.73)
71
+    - React-RCTNetwork (= 0.60.0-microsoft.73)
72
+    - React-RCTWebSocket (= 0.60.0-microsoft.73)
73
+  - React-RCTImage (0.60.0-microsoft.73):
74
+    - React-Core (= 0.60.0-microsoft.73)
75
+    - React-RCTNetwork (= 0.60.0-microsoft.73)
76
+  - React-RCTLinking (0.60.0-microsoft.73):
77
+    - React-Core (= 0.60.0-microsoft.73)
78
+  - React-RCTNetwork (0.60.0-microsoft.73):
79
+    - React-Core (= 0.60.0-microsoft.73)
80
+  - React-RCTSettings (0.60.0-microsoft.73):
81
+    - React-Core (= 0.60.0-microsoft.73)
82
+  - React-RCTText (0.60.0-microsoft.73):
83
+    - React-Core (= 0.60.0-microsoft.73)
84
+  - React-RCTVibration (0.60.0-microsoft.73):
85
+    - React-Core (= 0.60.0-microsoft.73)
86
+  - React-RCTWebSocket (0.60.0-microsoft.73):
87
+    - React-Core (= 0.60.0-microsoft.73)
88
+    - React-fishhook (= 0.60.0-microsoft.73)
89
+  - yoga (0.60.0-microsoft.73.React)
90
+
91
+DEPENDENCIES:
92
+  - boost-for-react-native (from `../../node_modules/react-native-macos/third-party-podspecs/boost-for-react-native.podspec`)
93
+  - DoubleConversion (from `../../node_modules/react-native-macos/third-party-podspecs/DoubleConversion.podspec`)
94
+  - Folly (from `../../node_modules/react-native-macos/third-party-podspecs/Folly.podspec`)
95
+  - glog (from `../../node_modules/react-native-macos/third-party-podspecs/glog.podspec`)
96
+  - React (from `../../node_modules/react-native-macos/`)
97
+  - React-Core (from `../../node_modules/react-native-macos/React`)
98
+  - React-cxxreact (from `../../node_modules/react-native-macos/ReactCommon/cxxreact`)
99
+  - React-DevSupport (from `../../node_modules/react-native-macos/React`)
100
+  - React-fishhook (from `../../node_modules/react-native-macos/Libraries/fishhook`)
101
+  - React-jscallinvoker (from `../../node_modules/react-native-macos/ReactCommon/jscallinvoker`)
102
+  - React-jsi (from `../../node_modules/react-native-macos/ReactCommon/jsi`)
103
+  - React-jsiexecutor (from `../../node_modules/react-native-macos/ReactCommon/jsiexecutor`)
104
+  - React-jsinspector (from `../../node_modules/react-native-macos/ReactCommon/jsinspector`)
105
+  - react-native-webview (from `../..`)
106
+  - React-RCTActionSheet (from `../../node_modules/react-native-macos/Libraries/ActionSheetIOS`)
107
+  - React-RCTAnimation (from `../../node_modules/react-native-macos/Libraries/NativeAnimation`)
108
+  - React-RCTBlob (from `../../node_modules/react-native-macos/Libraries/Blob`)
109
+  - React-RCTImage (from `../../node_modules/react-native-macos/Libraries/Image`)
110
+  - React-RCTLinking (from `../../node_modules/react-native-macos/Libraries/LinkingIOS`)
111
+  - React-RCTNetwork (from `../../node_modules/react-native-macos/Libraries/Network`)
112
+  - React-RCTSettings (from `../../node_modules/react-native-macos/Libraries/Settings`)
113
+  - React-RCTText (from `../../node_modules/react-native-macos/Libraries/Text`)
114
+  - React-RCTVibration (from `../../node_modules/react-native-macos/Libraries/Vibration`)
115
+  - React-RCTWebSocket (from `../../node_modules/react-native-macos/Libraries/WebSocket`)
116
+  - yoga (from `../../node_modules/react-native-macos/ReactCommon/yoga`)
117
+
118
+EXTERNAL SOURCES:
119
+  boost-for-react-native:
120
+    :podspec: "../../node_modules/react-native-macos/third-party-podspecs/boost-for-react-native.podspec"
121
+  DoubleConversion:
122
+    :podspec: "../../node_modules/react-native-macos/third-party-podspecs/DoubleConversion.podspec"
123
+  Folly:
124
+    :podspec: "../../node_modules/react-native-macos/third-party-podspecs/Folly.podspec"
125
+  glog:
126
+    :podspec: "../../node_modules/react-native-macos/third-party-podspecs/glog.podspec"
127
+  React:
128
+    :path: "../../node_modules/react-native-macos/"
129
+  React-Core:
130
+    :path: "../../node_modules/react-native-macos/React"
131
+  React-cxxreact:
132
+    :path: "../../node_modules/react-native-macos/ReactCommon/cxxreact"
133
+  React-DevSupport:
134
+    :path: "../../node_modules/react-native-macos/React"
135
+  React-fishhook:
136
+    :path: "../../node_modules/react-native-macos/Libraries/fishhook"
137
+  React-jscallinvoker:
138
+    :path: "../../node_modules/react-native-macos/ReactCommon/jscallinvoker"
139
+  React-jsi:
140
+    :path: "../../node_modules/react-native-macos/ReactCommon/jsi"
141
+  React-jsiexecutor:
142
+    :path: "../../node_modules/react-native-macos/ReactCommon/jsiexecutor"
143
+  React-jsinspector:
144
+    :path: "../../node_modules/react-native-macos/ReactCommon/jsinspector"
145
+  react-native-webview:
146
+    :path: "../.."
147
+  React-RCTActionSheet:
148
+    :path: "../../node_modules/react-native-macos/Libraries/ActionSheetIOS"
149
+  React-RCTAnimation:
150
+    :path: "../../node_modules/react-native-macos/Libraries/NativeAnimation"
151
+  React-RCTBlob:
152
+    :path: "../../node_modules/react-native-macos/Libraries/Blob"
153
+  React-RCTImage:
154
+    :path: "../../node_modules/react-native-macos/Libraries/Image"
155
+  React-RCTLinking:
156
+    :path: "../../node_modules/react-native-macos/Libraries/LinkingIOS"
157
+  React-RCTNetwork:
158
+    :path: "../../node_modules/react-native-macos/Libraries/Network"
159
+  React-RCTSettings:
160
+    :path: "../../node_modules/react-native-macos/Libraries/Settings"
161
+  React-RCTText:
162
+    :path: "../../node_modules/react-native-macos/Libraries/Text"
163
+  React-RCTVibration:
164
+    :path: "../../node_modules/react-native-macos/Libraries/Vibration"
165
+  React-RCTWebSocket:
166
+    :path: "../../node_modules/react-native-macos/Libraries/WebSocket"
167
+  yoga:
168
+    :path: "../../node_modules/react-native-macos/ReactCommon/yoga"
169
+
170
+SPEC CHECKSUMS:
171
+  boost-for-react-native: a110407d9db2642fd2e1bcd7c5a51c81f2521dc9
172
+  DoubleConversion: a1bc12a74baa397a2609e0f10e19b8062d864053
173
+  Folly: feff29ba9d0b7c2e4f793a94942831d6cc5bbad7
174
+  glog: b3f6d74f3e2d33396addc0ee724d2b2b79fc3e00
175
+  React: 4d79a1cdf3230e04aca581c25efee08da1ee5164
176
+  React-Core: 13ba8f1abdf6bcd5ff0f483a9ef7a2db9a107f0e
177
+  React-cxxreact: 11924907362f4cac7420b882760f939eb126ea26
178
+  React-DevSupport: ad7a5fc590659aeccfbf865fc4a134b70436d648
179
+  React-fishhook: 4990f5c5822d79c7ab3fb76c79ac17d09bee9336
180
+  React-jscallinvoker: 3a2e5ca0f66931ede7f55dfa2c3678983b668e86
181
+  React-jsi: 62b3cdf6e9a83d5c18dcf7dc895a362fb4b7853b
182
+  React-jsiexecutor: 8bd40a456b96ac807634225efa05ac2c35894dd0
183
+  React-jsinspector: c549193caebd0004cf2df489c57c5a24614c5516
184
+  react-native-webview: d75854c6508447f78d548dbdfbfc9a2049c3b1c5
185
+  React-RCTActionSheet: 7d7c2282c5a782e7a13f8da967eb2fe6ba296847
186
+  React-RCTAnimation: 289ab0e35a77a2f585fd2743b6abf7d52fac7a5b
187
+  React-RCTBlob: fff2b91fe158a258b72e610d5e0f77db4e059bef
188
+  React-RCTImage: cc560497ac826ca385dff28e631233ec8d1b95a6
189
+  React-RCTLinking: 6d4ed366a86755fba71a0446e5ee33e9944d8c0a
190
+  React-RCTNetwork: 15ce6970143dd7883db946b97d822098a1f9fc98
191
+  React-RCTSettings: 4729f1553af00f2f073a3e4a9743e6d35578afd6
192
+  React-RCTText: e5c12c5085188057d606c6627d8022c9983226b8
193
+  React-RCTVibration: 19f2176d53ccf811cc56dc333e538ae2f3a3822c
194
+  React-RCTWebSocket: ed4f366970f1cb6280a2edf6402aaebb224cd5ef
195
+  yoga: 94752fd7c7be3ab04256ef648abc656f52d77501
196
+
197
+PODFILE CHECKSUM: 57ba7807ee34b3b25a5ef3497860eaf96be05af7
198
+
199
+COCOAPODS: 1.8.4

+ 8
- 0
example/macos/example-iOS/AppDelegate.h View File

1
+#import <React/RCTBridgeDelegate.h>
2
+#import <UIKit/UIKit.h>
3
+
4
+@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
5
+
6
+@property (nonatomic, strong) UIWindow *window;
7
+
8
+@end

+ 35
- 0
example/macos/example-iOS/AppDelegate.m View File

1
+#import "AppDelegate.h"
2
+
3
+#import <React/RCTBridge.h>
4
+#import <React/RCTBundleURLProvider.h>
5
+#import <React/RCTRootView.h>
6
+
7
+@implementation AppDelegate
8
+
9
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
10
+{
11
+  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
12
+  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
13
+                                                   moduleName:@"example"
14
+                                            initialProperties:nil];
15
+
16
+  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
17
+
18
+  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
19
+  UIViewController *rootViewController = [UIViewController new];
20
+  rootViewController.view = rootView;
21
+  self.window.rootViewController = rootViewController;
22
+  [self.window makeKeyAndVisible];
23
+  return YES;
24
+}
25
+
26
+- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
27
+{
28
+#if DEBUG
29
+  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"example/index" fallbackResource:nil];
30
+#else
31
+  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
32
+#endif
33
+}
34
+
35
+@end

+ 42
- 0
example/macos/example-iOS/Base.lproj/LaunchScreen.xib View File

1
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
3
+    <dependencies>
4
+        <deployment identifier="iOS"/>
5
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
6
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
7
+    </dependencies>
8
+    <objects>
9
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
10
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
11
+        <view contentMode="scaleToFill" id="iN0-l3-epB">
12
+            <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
13
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
14
+            <subviews>
15
+                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
16
+                    <rect key="frame" x="20" y="439" width="441" height="21"/>
17
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
18
+                    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
19
+                    <nil key="highlightedColor"/>
20
+                </label>
21
+                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="example" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
22
+                    <rect key="frame" x="20" y="140" width="441" height="43"/>
23
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
24
+                    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
25
+                    <nil key="highlightedColor"/>
26
+                </label>
27
+            </subviews>
28
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
29
+            <constraints>
30
+                <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
31
+                <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
32
+                <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
33
+                <constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
34
+                <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
35
+                <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
36
+            </constraints>
37
+            <nil key="simulatedStatusBarMetrics"/>
38
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
39
+            <point key="canvasLocation" x="548" y="455"/>
40
+        </view>
41
+    </objects>
42
+</document>

+ 38
- 0
example/macos/example-iOS/Images.xcassets/AppIcon.appiconset/Contents.json View File

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
+}

+ 6
- 0
example/macos/example-iOS/Images.xcassets/Contents.json View File

1
+{
2
+  "info" : {
3
+    "version" : 1,
4
+    "author" : "xcode"
5
+  }
6
+}

+ 57
- 0
example/macos/example-iOS/Info.plist View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleDisplayName</key>
8
+	<string>$(PRODUCT_NAME)</string>
9
+	<key>CFBundleExecutable</key>
10
+	<string>$(EXECUTABLE_NAME)</string>
11
+	<key>CFBundleIdentifier</key>
12
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+	<key>CFBundleInfoDictionaryVersion</key>
14
+	<string>6.0</string>
15
+	<key>CFBundleName</key>
16
+	<string>$(PRODUCT_NAME)</string>
17
+	<key>CFBundlePackageType</key>
18
+	<string>APPL</string>
19
+	<key>CFBundleShortVersionString</key>
20
+	<string>1.0</string>
21
+	<key>CFBundleSignature</key>
22
+	<string>????</string>
23
+	<key>CFBundleVersion</key>
24
+	<string>1</string>
25
+	<key>LSRequiresIPhoneOS</key>
26
+	<true/>
27
+	<key>NSAppTransportSecurity</key>
28
+	<dict>
29
+		<key>NSAllowsArbitraryLoads</key>
30
+		<true/>
31
+		<key>NSExceptionDomains</key>
32
+		<dict>
33
+			<key>localhost</key>
34
+			<dict>
35
+				<key>NSExceptionAllowsInsecureHTTPLoads</key>
36
+				<true/>
37
+			</dict>
38
+		</dict>
39
+	</dict>
40
+	<key>NSLocationWhenInUseUsageDescription</key>
41
+	<string></string>
42
+	<key>UILaunchStoryboardName</key>
43
+	<string>LaunchScreen</string>
44
+	<key>UIRequiredDeviceCapabilities</key>
45
+	<array>
46
+		<string>armv7</string>
47
+	</array>
48
+	<key>UISupportedInterfaceOrientations</key>
49
+	<array>
50
+		<string>UIInterfaceOrientationPortrait</string>
51
+		<string>UIInterfaceOrientationLandscapeLeft</string>
52
+		<string>UIInterfaceOrientationLandscapeRight</string>
53
+	</array>
54
+	<key>UIViewControllerBasedStatusBarAppearance</key>
55
+	<false/>
56
+</dict>
57
+</plist>

+ 9
- 0
example/macos/example-iOS/main.m View File

1
+#import <UIKit/UIKit.h>
2
+
3
+#import "AppDelegate.h"
4
+
5
+int main(int argc, char * argv[]) {
6
+  @autoreleasepool {
7
+    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8
+  }
9
+}

+ 9
- 0
example/macos/example-macOS/AppDelegate.h View File

1
+#import <Cocoa/Cocoa.h>
2
+
3
+@class RCTBridge;
4
+
5
+@interface AppDelegate : NSObject <NSApplicationDelegate>
6
+
7
+@property (nonatomic, readonly) RCTBridge *bridge;
8
+
9
+@end

+ 0
- 0
example/macos/example-macOS/AppDelegate.m View File


Some files were not shown because too many files changed in this diff