added react-native demo

This commit is contained in:
Jake 2018-11-21 05:27:11 +02:00
parent 4896085d3a
commit 0ad2c74b79
78 changed files with 7049 additions and 0 deletions

View File

@ -0,0 +1,3 @@
{
"presets": ["module:metro-react-native-babel-preset"]
}

View File

@ -0,0 +1,6 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

View File

@ -0,0 +1,70 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
; Ignore polyfills
.*/Libraries/polyfills/.*
; Ignore metro
.*/node_modules/metro/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow/
node_modules/react-native/flow-github/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.system=haste
module.system.haste.use_name_reducers=true
# get basename
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
# strip .js or .js.flow suffix
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
# strip .ios suffix
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
munge_underscores=true
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
module.file_ext=.native.js
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[version]
^0.78.0

1
examples/react-native/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.pbxproj -text

56
examples/react-native/.gitignore vendored Normal file
View File

@ -0,0 +1,56 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle

View File

@ -0,0 +1 @@
{}

View File

View File

@ -0,0 +1,65 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
lib_deps = []
for jarfile in glob(['libs/*.jar']):
name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
lib_deps.append(':' + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
for aarfile in glob(['libs/*.aar']):
name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
lib_deps.append(':' + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "com.gundemo",
)
android_resource(
name = "res",
package = "com.gundemo",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)

View File

@ -0,0 +1,151 @@
apply plugin: "com.android.application"
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
project.ext.react = [
entryFile: "index.js"
]
apply from: "../../node_modules/react-native/react.gradle"
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.gundemo"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86"
}
}
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
compile project(':react-native-webview-bridge')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation "com.facebook.react:react-native:+" // From node_modules
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,26 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gundemo">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

View File

@ -0,0 +1,15 @@
package com.gundemo;
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "GunDemo";
}
}

View File

@ -0,0 +1,47 @@
package com.gundemo;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.github.alinz.reactnativewebviewbridge.WebViewBridgePackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new WebViewBridgePackage()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">GunDemo</string>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,39 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "27.0.3"
minSdkVersion = 16
compileSdkVersion = 27
targetSdkVersion = 26
supportLibVersion = "27.1.1"
}
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '4.4'
distributionUrl = distributionUrl.replace("bin", "all")
}

View File

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

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

172
examples/react-native/android/gradlew vendored Executable file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,8 @@
keystore(
name = "debug",
properties = "debug.keystore.properties",
store = "debug.keystore",
visibility = [
"PUBLIC",
],
)

View File

@ -0,0 +1,4 @@
key.store=debug.keystore
key.alias=androiddebugkey
key.store.password=android
key.alias.password=android

View File

@ -0,0 +1,5 @@
rootProject.name = 'GunDemo'
include ':react-native-webview-bridge'
project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
include ':app'

View File

@ -0,0 +1,4 @@
{
"name": "GunDemo",
"displayName": "GunDemo"
}

8
examples/react-native/index.js vendored Normal file
View File

@ -0,0 +1,8 @@
/** @format */
import './shim';
import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
console.disableYellowBox = true;

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSAppTransportSecurity</key>
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"GunDemo"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="GunDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View File

@ -0,0 +1,38 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>GunDemo</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSAppTransportSecurity</key>
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -0,0 +1,68 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
@interface GunDemoTests : XCTestCase
@end
@implementation GunDemoTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
{
if (test(view)) {
return YES;
}
for (UIView *subview in [view subviews]) {
if ([self findSubviewInView:subview matching:test]) {
return YES;
}
}
return NO;
}
- (void)testRendersWelcomeScreen
{
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
BOOL foundElement = NO;
__block NSString *redboxError = nil;
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
if (level >= RCTLogLevelError) {
redboxError = message;
}
});
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
return YES;
}
return NO;
}];
}
RCTSetLogFunction(RCTDefaultLogFunction);
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
}
@end

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,30 @@
{
"name": "GunDemo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"buffer": "^5.2.1",
"encode-utf8": "^1.0.2",
"fast-base64-encode": "^1.0.0",
"gun": "^0.9.99999",
"lodash": "^4.17.11",
"react": "16.6.1",
"react-native": "0.57.5",
"react-native-webview-bridge": "^0.40.1",
"serialize-error": "^3.0.0",
"text-encoding": "^0.7.0"
},
"devDependencies": {
"babel-jest": "23.6.0",
"jest": "23.6.0",
"metro-react-native-babel-preset": "0.49.2",
"react-test-renderer": "16.6.1"
},
"jest": {
"preset": "react-native"
}
}

20
examples/react-native/shim.js vendored Normal file
View File

@ -0,0 +1,20 @@
if (typeof __dirname === 'undefined') global.__dirname = '/'
if (typeof __filename === 'undefined') global.__filename = ''
if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer
const isDev = typeof __DEV__ === 'boolean' && __DEV__
process.env['NODE_ENV'] = isDev ? 'development' : 'production'
if (typeof localStorage !== 'undefined') {
localStorage.debug = isDev ? '*' : ''
}
global.location = {
protocol: 'file:',
host: '',
};
const { TextEncoder, TextDecoder } = require('text-encoding');
global.TextDecoder = TextDecoder;
global.TextEncoder = TextEncoder;

152
examples/react-native/src/App/Demo.js vendored Normal file
View File

@ -0,0 +1,152 @@
import * as React from 'react';
import {View, StyleSheet, TextInput, Text, TouchableOpacity, AsyncStorage} from 'react-native';
import Gun from 'gun/gun';
import 'gun/lib/open';
import '../extensions/sea';
import adapter from '../extensions/asyncStorageAdapter';
Gun.on('create', function(db) {
this.to.next(db);
const pluginInterop = function(middleware) {
return function(request) {
this.to.next(request);
return middleware(request, db);
};
}
// Register the adapter
db.on('get', pluginInterop(adapter.read));
db.on('put', pluginInterop(adapter.write));
});
export class Demo extends React.Component {
constructor() {
super();
this.gun = new Gun();
this.user = this.gun.user();
window.gun = this.gun;
window.user = this.user;
this.state = {
authenticated: false,
list: [],
listText: '',
username: '',
password: '',
}
}
hookUserList = () => {
this.user.get('list').open((list) => {
const userList = Object.keys(list).reduce((newList, key) => {
if (!!Object.keys(list[key]).length) {
return [...newList, {text: list[key].text, key}];
};
}, []);
this.setState({
list: userList || [],
});
});
}
addToList = () => {
this.user.get('list').set({text: this.state.listText});
}
doSignin = () => {
this.user.auth(this.state.username, this.state.password, (d) => {
if (d.err) {
console.log('err', d.err);
return;
}
this.setState({authenticated: true});
this.hookUserList();
});
}
doSignup = () => {
this.user.create(this.state.username, this.state.password, () => {
this.doSignin();
});
}
loginScreen = () => {
return (
<View style={styles.sub}>
<TextInput placeholder="username" onChangeText={(username) => this.setState({username})} value={this.state.username} style={styles.input} />
<TextInput placeholder="password" secureTextEntry={true} onChangeText={(password) => this.setState({password})} value={this.state.password} style={styles.input} />
<TouchableOpacity onPress={this.doSignin} style={styles.button}>
<Text>Sign in</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.doSignup} style={styles.button}>
<Text>Sign up</Text>
</TouchableOpacity>
</View>
)
}
userListScreen = () => {
return (
<View style={styles.sub}>
{
!!this.state.list.length && this.state.list.map((item) => <Text key={item.key}>* {item.text}</Text>)
}
<TextInput placeholder="text here" onChangeText={(listText) => this.setState({listText})} value={this.state.listText} style={styles.input} />
<TouchableOpacity onPress={this.addToList} style={styles.button}>
<Text>Add to list</Text>
</TouchableOpacity>
</View>
)
}
render() {
return (
<View style={styles.container}>
{
this.state.authenticated ?
this.userListScreen() : this.loginScreen()
}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
},
sub: {
height: '50%',
width: '60%',
justifyContent: 'space-between',
padding: 4,
},
button: {
backgroundColor: 'rgba(0, 0, 0, 0.3)',
borderWidth: 1,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: 50,
},
input: {
borderColor: 'black',
borderWidth: 1,
borderRadius: 5,
width: '100%',
height: 50,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: '32%',
},
});

View File

@ -0,0 +1,92 @@
import * as React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import WebViewBridge from 'react-native-webview-bridge';
import { MainWorker, webViewWorkerString } from '../webview-crypto';
import encodeUtf8 from 'encode-utf8';
import encodeBase64 from 'fast-base64-encode';
const base64EncodeString = (input) => {
return encodeBase64(new Uint8Array(encodeUtf8(input)));
};
const internalLibIOS = `
${webViewWorkerString}
(function () {
var wvw = new WebViewWorker(WebViewBridge.send.bind(WebViewBridge));
WebViewBridge.onMessage = wvw.onMainMessage.bind(wvw);
}());
`;
const intermediateLib = `
${webViewWorkerString}
(function () {
var wvw = new WebViewWorker(WebViewBridge.send.bind(WebViewBridge));
WebViewBridge.onMessage = wvw.onMainMessage.bind(wvw);
}());
`;
const internalLibAndroid = `eval(window.atob('${base64EncodeString(intermediateLib)}'))`;
export default class PolyfillCrypto extends React.Component {
shouldComponentUpdate() {
return false;
}
render() {
let worker;
const uri = 'file:///android_asset/html/blank.html';
return (
<View style={styles.hidden}>
<WebViewBridge
ref={(c) => {
if (c && !worker) {
worker = new MainWorker(c.sendToBridge, this.props.debug);
if (window.crypto) {
// we are in chrome debugger
// this means overridng the crypto object itself won't
// work, so we have to override all of it's methods
for (const name in worker.crypto.subtle) {
window.crypto.subtle[name] = worker.crypto.subtle[name];
}
window.crypto.fake = true;
} else {
window.crypto = worker.crypto;
}
window.crypto.loaded = true;
console.log('*** poly injected', window.crypto);
}
}}
onBridgeMessage={
// can't refer to this.state.onBridgeMessage directly
// because it is not defined when this component is first
// started, only set in `ref`
(message) => {
worker.onWebViewMessage(message);
}
}
injectedJavaScript={
Platform.OS === 'android' ? internalLibAndroid : internalLibIOS
}
onError={(error) => {
console.warn('Error creating webview: ', error);
}}
javaScriptEnabled={true}
source={{
uri: Platform.OS === 'android' ? uri : 'about:blank',
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
hidden: {
height: 0,
opacity: 0,
},
});

26
examples/react-native/src/App/app.js vendored Normal file
View File

@ -0,0 +1,26 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/
import React, {Component} from 'react';
import {View} from 'react-native';
import {Demo} from './Demo';
import PolyFillCrypto from './PolyFillCrypto';
export class App extends Component {
render() {
return (
<View>
<PolyFillCrypto />
<Demo/>
</View>
);
}
}

View File

@ -0,0 +1 @@
export {App as default} from './app';

View File

@ -0,0 +1,75 @@
import * as Gun from 'gun';
import { AsyncStorage } from 'react-native';
const readNode = (key, cb) => {
AsyncStorage.getItem(key || '', cb);
};
const read = (request, db) => {
const { get } = request;
const dedupid = request['#'];
const key = get['#'];
const field = get['.'];
const done = (err, data) => {
if (!data && !err) {
db.on('in', {
'@': dedupid,
put: null,
err: null,
});
} else {
db.on('in', {
'@': dedupid,
put: Gun.graph.node(data),
err,
});
}
};
const acknowledgeRet = (err, result) => {
if (err) {
done(err);
} else if (result === null) {
// Nothing found
done(null);
} else {
const temp = JSON.parse(result);
if (field) {
done(null, temp[field] || null);
} else {
done(null, temp);
}
}
};
readNode(key || '', acknowledgeRet);
};
const write = (request, db) => {
const { put: graph } = request;
const keys = Object.keys(graph);
const dedupid = graph['#'];
const instructions = keys.map((key) => {
return [key, JSON.stringify(graph[key] || {})];
});
AsyncStorage.multiMerge(instructions, (err) => {
db.on('in', {
'#': dedupid,
ok: !err || err.length === 0,
err,
});
});
};
// This returns a promise, it can be awaited!
const reset = () => AsyncStorage.clear();
export default {
read,
write,
reset,
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
export default class MainWorker {
private sendToWebView;
private debug;
readonly crypto: Crypto;
private readonly subtle;
private static uuid;
private toSend;
private readyToSend;
private messages;
constructor(sendToWebView: (message: string) => void, debug?: boolean);
onWebViewMessage(message: string): void;
private getRandomValues;
private callMethod;
}

View File

@ -0,0 +1,170 @@
import serializeError from 'serialize-error';
import { parse, stringify } from './serializeBinary';
const SUBTLE_METHODS = [
'encrypt',
'decrypt',
'sign',
'verify',
'digest',
'generateKey',
'deriveKey',
'deriveBits',
'importKey',
'exportKey',
'wrapKey',
'unwrapKey',
];
/*
MainWorker provides a `crypto` attribute that proxies method calls
to the webview.
It sends strings to the webview in the format:
{
id: <id>,
method: getRandomValues | subtle.<method name>,
args: [<serialized arg>]
}
When the webview succeeds in completeing that method, it gets backs:
{
id: <id>,
value: <serialized return value>
}
And when it fails:
{
id: <id>,
reason: <serialized rejected reason>,
}
*/
export default class MainWorker {
// sendToWebView should take a string and send that message to the webview
constructor(sendToWebView, debug = false) {
this.sendToWebView = sendToWebView;
this.debug = debug;
// hold a queue of messages to send, in case someone calls crypto
// before the webview is initialized
this.toSend = [];
this.readyToSend = false;
// Holds the `resolve` and `reject` function for all the promises
// we are working on
this.messages = {};
}
get crypto() {
const callMethod = this.callMethod;
return {
subtle: this.subtle,
getRandomValues: this.getRandomValues.bind(this),
fake: true,
};
}
get subtle() {
const s = {};
for (const m of SUBTLE_METHODS) {
s[m] = (...args) => {
return this.callMethod(`subtle.${m}`, args, true);
};
}
return s;
}
// http://stackoverflow.com/a/105074/907060
static uuid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return `${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}`;
}
onWebViewMessage(message) {
// first message just tells us the webview is ready
if (!this.readyToSend) {
if (this.debug) {
console.log('[webview-crypto] Got first message; ready to send');
}
this.readyToSend = true;
for (const m of this.toSend) {
this.sendToWebView(m);
}
return;
}
parse(message)
.then(({ id, value, reason }) => {
if (this.debug) {
console.log('[webview-crypto] Received message:', JSON.stringify({
id,
value,
reason,
}));
}
if (!id) {
console.warn('[webview-crypto] no ID passed back from message:', JSON.stringify(serializeError(reason)));
return;
}
const { resolve, reject } = this.messages[id];
if (value) {
resolve(value);
}
else {
reject(reason);
}
delete this.messages[id];
})
.catch((reason) => {
console.warn('[webview-crypto] error in `parse` of message:', JSON.stringify(message), 'reason:', JSON.stringify(serializeError(reason)));
});
}
getRandomValues(array) {
const promise = this.callMethod('getRandomValues', [array], false);
// make the _promise not enumerable so it isn't JSON stringified,
// which could lead to an infinite loop with Angular's zone promises
Object.defineProperty(array, '_promise', {
value: promise,
configurable: true,
enumerable: false,
writable: true,
});
promise.then((updatedArray) => {
array.set(updatedArray);
});
return array;
}
callMethod(method, args, waitForArrayBufferView) {
const id = MainWorker.uuid();
// store this promise, so we can resolve it when we get a message
// back from the web view
const promise = new Promise((resolve, reject) => {
this.messages[id] = { resolve, reject };
});
const payloadObject = { method, id, args };
if (this.debug) {
console.log('[webview-crypto] Sending message:', JSON.stringify({
method,
args,
payloadObject,
}));
}
stringify(payloadObject, waitForArrayBufferView)
.then((message) => {
if (this.readyToSend) {
this.sendToWebView(message);
}
else {
this.toSend.push(message);
}
})
.catch((reason) => {
this.messages[id].reject({
message: `exception in stringify-ing message: ${method} ${id}`,
reason,
});
delete this.messages[id];
});
return promise;
}
}
//# sourceMappingURL=MainWorker.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"MainWorker.js","sourceRoot":"","sources":["../src/MainWorker.ts"],"names":[],"mappings":"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"}

View File

@ -0,0 +1,6 @@
export declare class WebViewWorker {
private sendToMain;
constructor(sendToMain: (message: string) => void);
onMainMessage(message: string): Promise<void>;
send(data: any): Promise<void>;
}

View File

@ -0,0 +1,75 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import serializeError from 'serialize-error';
import { subtle } from './compat';
import { parse, stringify } from './serializeBinary';
export class WebViewWorker {
constructor(sendToMain) {
this.sendToMain = sendToMain;
sendToMain('We are ready!');
}
onMainMessage(message) {
return __awaiter(this, void 0, void 0, function* () {
let id;
let method;
let args;
try {
({ id, method, args } = yield parse(message));
}
catch (e) {
yield this.send({
reason: `Couldn't parse data: ${e}`,
});
return;
}
let value;
try {
if (method === 'getRandomValues') {
value = crypto.getRandomValues(args[0]);
}
else {
const methodName = method.split('.')[1];
console.log(methodName, args);
value = yield subtle()[methodName].apply(subtle(), args);
// if we import a crypto key, we want to save how we imported it
// so we can send that back and re-create the key later
if (methodName === 'importKey') {
value._import = {
format: args[0],
keyData: args[1],
};
}
}
}
catch (e) {
yield this.send({ id, reason: serializeError(e) });
return;
}
yield this.send({ id, value });
});
}
send(data) {
return __awaiter(this, void 0, void 0, function* () {
let message;
try {
message = yield stringify(data);
}
catch (e) {
const newData = {
id: data.id,
reason: `stringify error ${e}`,
};
this.sendToMain(JSON.stringify(newData));
return;
}
this.sendToMain(message);
});
}
}
//# sourceMappingURL=WebViewWorker.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"WebViewWorker.js","sourceRoot":"","sources":["../src/WebViewWorker.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,cAAc,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,OAAO,aAAa;IACzB,YAAoB,UAAqC;QAArC,eAAU,GAAV,UAAU,CAA2B;QACxD,UAAU,CAAC,eAAe,CAAC,CAAC;IAC7B,CAAC;IAEK,aAAa,CAAC,OAAe;;YAClC,IAAI,EAAU,CAAC;YACf,IAAI,MAAc,CAAC;YACnB,IAAI,IAAW,CAAC;YAChB,IAAI;gBACH,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;aAC9C;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,IAAI,CAAC,IAAI,CAAC;oBACf,MAAM,EAAE,wBAAwB,CAAC,EAAE;iBACnC,CAAC,CAAC;gBACH,OAAO;aACP;YACD,IAAI,KAAK,CAAC;YAEV,IAAI;gBACH,IAAI,MAAM,KAAK,iBAAiB,EAAE;oBACjC,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;iBACxC;qBAAM;oBACN,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;oBACxC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;oBAC9B,KAAK,GAAG,MAAO,MAAM,EAAU,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;oBAElE,gEAAgE;oBAChE,uDAAuD;oBACvD,IAAI,UAAU,KAAK,WAAW,EAAE;wBAC/B,KAAK,CAAC,OAAO,GAAG;4BACf,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;4BACf,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;yBAChB,CAAC;qBACF;iBACD;aACD;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAG,cAAsB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC5D,OAAO;aACP;YACD,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChC,CAAC;KAAA;IAEK,IAAI,CAAC,IAAS;;YACnB,IAAI,OAAe,CAAC;YACpB,IAAI;gBACH,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,OAAO,GAAG;oBACf,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,MAAM,EAAE,mBAAmB,CAAC,EAAE;iBAC9B,CAAC;gBACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBACzC,OAAO;aACP;YACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;KAAA;CACD"}

View File

@ -0,0 +1,8 @@
export interface ISerializer<T, S> {
id: string;
isType: (o: any) => boolean;
toObject?: (t: T) => Promise<S>;
fromObject?: (o: S) => Promise<T>;
}
export declare function toObjects(serializers: Array<ISerializer<any, any>>, o: any): Promise<any>;
export declare function fromObjects(serializers: Array<ISerializer<any, any>>, o: any): Promise<any>;

View File

@ -0,0 +1,56 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
// tslint:disable
import find from 'lodash/find';
class Serialized {
}
function isSerialized(object) {
return object.hasOwnProperty('__serializer_id');
}
export function toObjects(serializers, o) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof o !== 'object') {
return o;
}
const serializer = find(serializers, (s) => s.isType(o));
if (serializer) {
const value = serializer.toObject ? yield serializer.toObject(o) : o;
return {
__serializer_id: serializer.id,
value: yield toObjects(serializers, value),
};
}
const newO = o instanceof Array ? [] : {};
for (const atr in o) {
newO[atr] = yield toObjects(serializers, o[atr]);
}
return newO;
});
}
export function fromObjects(serializers, o) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof o !== 'object') {
return o;
}
if (isSerialized(o)) {
const value = yield fromObjects(serializers, o.value);
const serializer = find(serializers, ['id', o.__serializer_id]) || {};
if (serializer.fromObject) {
return serializer.fromObject(value);
}
return value;
}
const newO = o instanceof Array ? [] : {};
for (const atr in o) {
newO[atr] = yield fromObjects(serializers, o[atr]);
}
return newO;
});
}
//# sourceMappingURL=asyncSerialize.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"asyncSerialize.js","sourceRoot":"","sources":["../src/asyncSerialize.ts"],"names":[],"mappings":";;;;;;;;AAAA,iBAAiB;AACjB,OAAO,IAAI,MAAM,aAAa,CAAC;AAS/B,MAAM,UAAU;CAIf;AAED,SAAS,YAAY,CAAC,MAAW;IAChC,OAAO,MAAM,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAgB,SAAS,CAC9B,WAAyC,EACzC,CAAM;;QAEN,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YAC1B,OAAO,CAAC,CAAC;SACT;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAI,UAAU,EAAE;YACf,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrE,OAAO;gBACN,eAAe,EAAE,UAAU,CAAC,EAAE;gBAC9B,KAAK,EAAE,MAAM,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC;aAC5B,CAAC;SAChB;QAED,MAAM,IAAI,GAAQ,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE;YACpB,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACjD;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CAAA;AAED,MAAM,UAAgB,WAAW,CAChC,WAAyC,EACzC,CAAM;;QAEN,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YAC1B,OAAO,CAAC,CAAC;SACT;QAED,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE;YACpB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,EAAS,CAAC;YAC7E,IAAI,UAAU,CAAC,UAAU,EAAE;gBAC1B,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aACpC;YACD,OAAO,KAAK,CAAC;SACb;QAED,MAAM,IAAI,GAAQ,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE;YACpB,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACnD;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CAAA"}

View File

@ -0,0 +1 @@
export declare function subtle(): SubtleCrypto;

View File

@ -0,0 +1,4 @@
export function subtle() {
return window.crypto.subtle || window.crypto.webkitSubtle;
}
//# sourceMappingURL=compat.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"compat.js","sourceRoot":"","sources":["../src/compat.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM;IACrB,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,IAAK,MAAM,CAAC,MAAc,CAAC,YAAY,CAAC;AACpE,CAAC"}

View File

@ -0,0 +1,3 @@
import MainWorker from './MainWorker';
import webViewWorkerString from './webViewWorkerString';
export { MainWorker, webViewWorkerString };

View File

@ -0,0 +1,4 @@
import MainWorker from './MainWorker';
import webViewWorkerString from './webViewWorkerString';
export { MainWorker, webViewWorkerString };
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC"}

View File

@ -0,0 +1,5 @@
export declare function parse(text: string): Promise<any>;
export declare function stringify(value: any, waitForArrayBufferView?: boolean): Promise<string>;
export interface IArrayBufferViewWithPromise extends ArrayBufferView {
_promise?: Promise<ArrayBufferView>;
}

View File

@ -0,0 +1,160 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { fromObjects, toObjects } from './asyncSerialize';
import { subtle } from './compat';
export function parse(text) {
return __awaiter(this, void 0, void 0, function* () {
// need decodeURIComponent so binary strings are transfered properly
const deocodedText = unescape(text);
const objects = JSON.parse(deocodedText);
return fromObjects(serializers(true), objects);
});
}
export function stringify(value, waitForArrayBufferView = true) {
return __awaiter(this, void 0, void 0, function* () {
const serialized = yield toObjects(serializers(waitForArrayBufferView), value);
// need encodeURIComponent so binary strings are transfered properly
const message = JSON.stringify(serialized);
return escape(message);
});
}
function serializers(waitForArrayBufferView) {
return [
ArrayBufferSerializer,
ArrayBufferViewSerializer(waitForArrayBufferView),
CryptoKeySerializer,
];
}
const ArrayBufferSerializer = {
id: 'ArrayBuffer',
isType: (o) => o instanceof ArrayBuffer,
// from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
// modified to use Int8Array so that we can hold odd number of bytes
toObject: (ab) => __awaiter(this, void 0, void 0, function* () {
return String.fromCharCode.apply(null, new Int8Array(ab));
}),
fromObject: (data) => __awaiter(this, void 0, void 0, function* () {
const buf = new ArrayBuffer(data.length);
const bufView = new Int8Array(buf);
for (let i = 0, strLen = data.length; i < strLen; i++) {
bufView[i] = data.charCodeAt(i);
}
return buf;
}),
};
function isArrayBufferViewWithPromise(obj) {
return obj.hasOwnProperty('_promise');
}
// Normally we could just do `abv.constructor.name`, but in
// JavaScriptCore, this wont work for some weird reason.
// list from https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView
function arrayBufferViewName(abv) {
if (abv instanceof Int8Array) {
return 'Int8Array';
}
if (abv instanceof Uint8Array) {
return 'Uint8Array';
}
if (abv instanceof Uint8ClampedArray) {
return 'Uint8ClampedArray';
}
if (abv instanceof Int16Array) {
return 'Int16Array';
}
if (abv instanceof Uint16Array) {
return 'Uint16Array';
}
if (abv instanceof Int32Array) {
return 'Int32Array';
}
if (abv instanceof Uint32Array) {
return 'Uint32Array';
}
if (abv instanceof Float32Array) {
return 'Float32Array';
}
if (abv instanceof Float64Array) {
return 'Float64Array';
}
if (abv instanceof DataView) {
return 'DataView';
}
return '';
}
function ArrayBufferViewSerializer(waitForPromise) {
return {
id: 'ArrayBufferView',
isType: ArrayBuffer.isView,
toObject: (abv) => __awaiter(this, void 0, void 0, function* () {
if (waitForPromise) {
// wait for promise to resolve if the abv was returned from getRandomValues
if (isArrayBufferViewWithPromise(abv)) {
yield abv._promise;
}
}
return {
name: arrayBufferViewName(abv),
buffer: abv.buffer,
};
}),
fromObject: (abvs) => __awaiter(this, void 0, void 0, function* () {
// tslint:disable-next-line
return eval(`new ${abvs.name}(abvs.buffer)`);
}),
};
}
function hasData(ck) {
return ck._import !== undefined;
}
const CryptoKeySerializer = {
id: 'CryptoKey',
isType: (o) => {
const localStr = o.toLocaleString();
// can't use CryptoKey or constructor on WebView iOS
const isCryptoKey = localStr === '[object CryptoKey]' || localStr === '[object Key]';
const isCryptoKeyWithData = o._import && !o.serialized;
return isCryptoKey || isCryptoKeyWithData;
},
toObject: (ck) => __awaiter(this, void 0, void 0, function* () {
// if we already have the import serialized, just return that
if (hasData(ck)) {
return {
serialized: true,
_import: ck._import,
type: ck.type,
extractable: ck.extractable,
algorithm: ck.algorithm,
usages: ck.usages,
};
}
const jwk = yield subtle().exportKey('jwk', ck);
return {
_import: {
format: 'jwk',
keyData: jwk,
},
serialized: true,
algorithm: ck.algorithm,
extractable: ck.extractable,
usages: ck.usages,
type: ck.type,
};
}),
fromObject: (cks) => __awaiter(this, void 0, void 0, function* () {
// if we don't have access to to a real crypto implementation, just return
// the serialized crypto key
if (crypto.fake) {
const newCks = Object.assign({}, cks);
delete newCks.serialized;
return newCks;
}
return subtle().importKey(cks._import.format, cks._import.keyData, cks.algorithm, cks.extractable, cks.usages);
}),
};
//# sourceMappingURL=serializeBinary.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"serializeBinary.js","sourceRoot":"","sources":["../src/serializeBinary.ts"],"names":[],"mappings":"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"}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{"version":3,"file":"webViewWorkerString.js","sourceRoot":"","sources":["../src/webViewWorkerString.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+M9B,CAAC;AAEF,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAq4Dd,CAAC"}