Merge pull request #4 from testfairy/feat-android-sdk

Add Android SDK support
This commit is contained in:
Vijay Sharma 2016-04-11 10:57:47 -04:00
commit 5f0b593a7c
32 changed files with 1007 additions and 244 deletions

View File

@ -15,16 +15,60 @@ TestFairyBridge
* SystemConfiguration.framework * SystemConfiguration.framework
* OpenGLES.framework * OpenGLES.framework
## Usage ## Manual installation Android
Once the native library has been added to your project, you can now enable session recording with TestFairy. You will need an iOS app token, which you can get from your [preferences](http://app.testfairy.com/settings/) page on your TestFairy account.
Next, from your JavaScript file, (index.ios.js for example), import the TestFairy bridge into your project, and invoke `begin` passing in the iOS app token. Best time to invoke `begin` is usually before you register you Application. ```gradle
// file: android/settings.gradle
...
include ':react-native-testfairy'
project(':react-native-testfairy').projectDir = new File(settingsDir, '../node_modules/react-native-testfairy/android')
```
```gradle
// file: android/app/build.gradle
...
dependencies {
...
compile project(path: ':react-native-testfairy')
}
```
```java
// file: MainActivity.java
...
import com.testfairy.react.TestFairyPackage; // import package
public class MainActivity extends ReactActivity {
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new TestFairyPackage() // Add package
);
}
...
}
```
## Usage
Once the native library has been added to your project, you can now enable session recording with TestFairy. You will need an app token, which you can get from your [preferences](http://app.testfairy.com/settings/) page on your TestFairy account.
Next, from your JavaScript file, (index.ios.js for example), import the TestFairy bridge into your project, and invoke `begin` passing in the app token. Best time to invoke `begin` is usually in `componentWillMount` or right before you register your application.
``` ```
const TestFairy = require('react-native-testfairy'); const TestFairy = require('react-native-testfairy');
... ...
TestFairy.begin('<insert ios app token here>'); componentWillMount: function() {
AppRegistry.registerComponent('app', () => App); TestFairy.begin('<insert ios app token here>');
}
``` ```
And that's it! You can now log into your [account](http://app.testfairy.com) and view your sessions. Also, feel free to refer to the [documentation](https://github.com/testfairy/react-native-testfairy/blob/master/index.js) for other available APIs. And that's it! You can now log into your [account](http://app.testfairy.com) and view your sessions. Also, feel free to refer to the [documentation](https://github.com/testfairy/react-native-testfairy/blob/master/index.js) for other available APIs.
@ -38,28 +82,43 @@ In order to hide views from your recorded session, you will need to pass a refer
<Text ref="instructions">This will be hidden</Text> <Text ref="instructions">This will be hidden</Text>
``` ```
Next, in a component callback, such as `componentDidMount`, pass the reference ID back to TestFairy by invoking `hideView`. You will need to import `findNodeHandle` into your project. Next, in a component callback, such as `componentDidMount`, pass the reference ID back to TestFairy by invoking `hideView`.
``` ```
var { findNodeHandle } = React;
const TestFairy = require('react-native-testfairy'); const TestFairy = require('react-native-testfairy');
... ...
var MyComponent = React.createClass({ var MyComponent = React.createClass({
... ...
componentWillMount: function() {
TestFairy.begin('<insert ios app token here>');
},
componentDidMount: function() { componentDidMount: function() {
TestFairyBridge.hideView(findNodeHandle(this.refs.instructions)); TestFairyBridge.hideView(this.refs.instructions);
}, },
... ...
render: function() { render: function() {
return (<Text ref="instructions">This will be hidden</Text>); return (<Text ref="instructions">This will be hidden</Text>);
} }
}); });
TestFairy.begin('<insert ios app token here>');
``` ```
Now, your Views will be hidden before any video is uploaded to TestFairy. Now, your Views will be hidden before any video is uploaded to TestFairy.
## Migrating from 1.x to 2.x
In order to migrate from 1.x to 2.x, a minor change is required in the way you hide views.
Remove the import of `findNodeHandle`
```
- var { findNodeHandle } = React;
```
Pass the `ref` object directly into `TestFairy.hideView()`
```
- TestFairyBridge.hideView(findNodeHandle(this.refs.instructions));
+ TestFairyBridge.hideView(this.refs.instructions);
```
License License
======= =======

24
android/build.gradle Normal file
View File

@ -0,0 +1,24 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.facebook.react:react-native:0.20.1'
compile 'testfairy:testfairy-android-sdk:1.1.0'
}

View File

@ -0,0 +1,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testfairy.react">
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@ -0,0 +1,146 @@
package com.testfairy.react;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.testfairy.TestFairy;
import java.util.Map;
public class TestFairyModule extends ReactContextBaseJavaModule {
public TestFairyModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "TestFairyBridge";
}
@ReactMethod
public void begin(final String appKey, ReadableMap map) {
runOnUi(new Runnable() {
@Override
public void run() {
TestFairy.begin(getReactApplicationContext(), appKey);
}
});
}
@ReactMethod
public void setCorrelationId(final String correlationId) {
runOnUi(new Runnable() {
@Override
public void run() {
TestFairy.setCorrelationId(correlationId);
}
});
}
@ReactMethod
public void identify(final String identity, ReadableMap map) {
runOnUi(new Runnable() {
@Override
public void run() {
final Map<String, String> traits = null;
TestFairy.identify(identity, traits);
}
});
}
@ReactMethod
public void takeScreenshot() {
// TODO: Does not exist on Android
}
@ReactMethod
public void pause() {
runOnUi(new Runnable() {
@Override
public void run() {
TestFairy.pause();
}
});
}
@ReactMethod
public void resume() {
runOnUi(new Runnable() {
@Override
public void run() {
TestFairy.resume();
}
});
}
@ReactMethod
public void checkpoint(final String checkpoint) {
runOnUi(new Runnable() {
@Override
public void run() {
TestFairy.addCheckpoint(checkpoint);
}
});
}
@ReactMethod
public void sendUserFeedback(final String feedback) {
runOnUi(new Runnable() {
@Override
public void run() {
TestFairy.sendUserFeedback(feedback);
}
});
}
@ReactMethod
public void sessionUrl(final Callback callback) {
runOnUi(new Runnable() {
@Override
public void run() {
callback.invoke(TestFairy.getSessionUrl());
}
});
}
@ReactMethod
public void version(final Callback callback) {
runOnUi(new Runnable() {
@Override
public void run() {
callback.invoke(TestFairy.getSessionUrl());
}
});
}
@ReactMethod
public void hideView(final int tag) {
runOnUi(new Runnable() {
@Override
public void run() {
Activity activity = getCurrentActivity();
if (activity == null)
return;
View view = activity.findViewById(tag);
if (view == null)
return;
TestFairy.hideView(view);
}
});
}
private void runOnUi(Runnable runnable) {
UiThreadUtil.runOnUiThread(runnable);
}
}

View File

@ -0,0 +1,31 @@
package com.testfairy.react;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestFairyPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new TestFairyModule(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@ -14,17 +14,21 @@
# Ignore react and fbjs where there are overlaps, but don't ignore # Ignore react and fbjs where there are overlaps, but don't ignore
# anything that react-native relies on # anything that react-native relies on
.*/node_modules/fbjs-haste/.*/__tests__/.* .*/node_modules/fbjs/lib/Map.js
.*/node_modules/fbjs-haste/__forks__/Map.js .*/node_modules/fbjs/lib/fetch.js
.*/node_modules/fbjs-haste/__forks__/Promise.js .*/node_modules/fbjs/lib/ExecutionEnvironment.js
.*/node_modules/fbjs-haste/__forks__/fetch.js .*/node_modules/fbjs/lib/ErrorUtils.js
.*/node_modules/fbjs-haste/core/ExecutionEnvironment.js
.*/node_modules/fbjs-haste/core/isEmpty.js # Flow has a built-in definition for the 'react' module which we prefer to use
.*/node_modules/fbjs-haste/crypto/crc32.js # over the currently-untyped source
.*/node_modules/fbjs-haste/stubs/ErrorUtils.js .*/node_modules/react/react.js
.*/node_modules/react-haste/React.js .*/node_modules/react/lib/React.js
.*/node_modules/react-haste/renderers/dom/ReactDOM.js .*/node_modules/react/lib/ReactDOM.js
.*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
.*/__mocks__/.*
.*/__tests__/.*
.*/commoner/test/source/widget/share.js
# Ignore commoner tests # Ignore commoner tests
.*/node_modules/commoner/test/.* .*/node_modules/commoner/test/.*
@ -38,26 +42,48 @@
# Ignore Website # Ignore Website
.*/website/.* .*/website/.*
.*/node_modules/is-my-json-valid/test/.*\.json
.*/node_modules/iconv-lite/encodings/tables/.*\.json
.*/node_modules/y18n/test/.*\.json
.*/node_modules/spdx-license-ids/spdx-license-ids.json
.*/node_modules/spdx-exceptions/index.json
.*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json
.*/node_modules/resolve/lib/core.json
.*/node_modules/jsonparse/samplejson/.*\.json
.*/node_modules/json5/test/.*\.json
.*/node_modules/ua-parser-js/test/.*\.json
.*/node_modules/builtin-modules/builtin-modules.json
.*/node_modules/binary-extensions/binary-extensions.json
.*/node_modules/url-regex/tlds.json
.*/node_modules/joi/.*\.json
.*/node_modules/isemail/.*\.json
.*/node_modules/tr46/.*\.json
[include] [include]
[libs] [libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow
flow/
[options] [options]
module.system=haste module.system=haste
esproposal.class_static_fields=enable
esproposal.class_instance_fields=enable
munge_underscores=true munge_underscores=true
module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub' 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\)$' -> 'RelativeImageStub'
suppress_type=$FlowIssue suppress_type=$FlowIssue
suppress_type=$FlowFixMe suppress_type=$FlowFixMe
suppress_type=$FixMe suppress_type=$FixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
[version] [version]
0.19.0 0.22.0

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="TestFairy" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$USER_HOME$/testfairy/react-native/example/android" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

129
example/android/app/app.iml Normal file
View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$USER_HOME$/testfairy/react-native/example/android" external.system.id="GRADLE" external.system.module.group="TestFairy" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/debug" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/drawee/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fbcore/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fresco/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-okhttp/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.react/react-native/0.23.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/org.webkit/android-jsc/r174650/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/mockable-android-23.jar" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/tmp" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="okhttp-ws-2.5.0" level="project" />
<orderEntry type="library" exported="" name="library-2.4.0" level="project" />
<orderEntry type="library" exported="" name="okio-1.6.0" level="project" />
<orderEntry type="library" exported="" name="stetho-okhttp-1.2.0" level="project" />
<orderEntry type="library" exported="" name="okhttp-2.5.0" level="project" />
<orderEntry type="library" exported="" name="jsr305-3.0.0" level="project" />
<orderEntry type="library" exported="" name="stetho-1.2.0" level="project" />
<orderEntry type="library" exported="" name="jackson-core-2.2.3" level="project" />
<orderEntry type="library" exported="" name="fbcore-0.8.1" level="project" />
<orderEntry type="library" exported="" name="commons-cli-1.2" level="project" />
<orderEntry type="library" exported="" name="react-native-0.23.1" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-0.8.1" level="project" />
<orderEntry type="library" exported="" name="android-jsc-r174650" level="project" />
<orderEntry type="library" exported="" name="fresco-0.8.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-okhttp-0.8.1" level="project" />
<orderEntry type="library" exported="" name="bolts-android-1.1.4" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
<orderEntry type="library" exported="" name="drawee-0.8.1" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
<orderEntry type="module" module-name="react-native-testfairy" exported="" />
</component>
</module>

View File

@ -1,7 +1,10 @@
apply plugin: "com.android.application" apply plugin: "com.android.application"
import com.android.build.OutputFile
/** /**
* The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets. * 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 * 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 * 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 * bundle directly from the development server. Below you can see all the possible configurations
@ -21,6 +24,15 @@ apply plugin: "com.android.application"
* // whether to bundle JS and assets in release mode * // whether to bundle JS and assets in release mode
* bundleInRelease: true, * 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,
*
* // the root of your project, i.e. where "package.json" lives * // the root of your project, i.e. where "package.json" lives
* root: "../../", * root: "../../",
* *
@ -49,30 +61,68 @@ apply plugin: "com.android.application"
apply from: "react.gradle" apply from: "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 { android {
compileSdkVersion 23 compileSdkVersion 23
buildToolsVersion "23.0.1" buildToolsVersion "23.0.2"
defaultConfig { defaultConfig {
applicationId "com.testfairy" applicationId "com.testfairy.react.example"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 22 targetSdkVersion 22
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
ndk { ndk {
abiFilters "armeabi-v7a", "x86" abiFilters "armeabi-v7a", "x86"
} }
} }
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86"
}
}
buildTypes { buildTypes {
release { release {
minifyEnabled false // Set this to true to enable Proguard minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 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 { dependencies {
compile fileTree(dir: "libs", include: ["*.jar"]) compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1" compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.17.+" compile "com.facebook.react:react-native:+" // From node_modules
compile project(path: ':react-native-testfairy')
} }

View File

@ -40,9 +40,12 @@
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; } -keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; } -keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactProp <methods>; } -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup <methods>; } -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
# okhttp # okhttp
@ -58,3 +61,7 @@
-dontwarn java.nio.file.* -dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.** -dontwarn okio.**
# stetho
-dontwarn com.facebook.stetho.**

View File

@ -11,77 +11,87 @@ def elvisFile(thing) {
} }
def reactRoot = elvisFile(config.root) ?: file("../../") def reactRoot = elvisFile(config.root) ?: file("../../")
def jsBundleDirDebug = elvisFile(config.jsBundleDirDebug) ?:
file("$buildDir/intermediates/assets/debug")
def jsBundleDirRelease = elvisFile(config.jsBundleDirRelease) ?:
file("$buildDir/intermediates/assets/release")
def resourcesDirDebug = elvisFile(config.resourcesDirDebug) ?:
file("$buildDir/intermediates/res/merged/debug")
def resourcesDirRelease = elvisFile(config.resourcesDirRelease) ?:
file("$buildDir/intermediates/res/merged/release")
def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
def jsBundleFileDebug = file("$jsBundleDirDebug/$bundleAssetName") void runBefore(String dependentTaskName, Task task) {
def jsBundleFileRelease = file("$jsBundleDirRelease/$bundleAssetName") Task dependentTask = tasks.findByPath(dependentTaskName);
if (dependentTask != null) {
task bundleDebugJsAndAssets(type: Exec) { dependentTask.dependsOn task
// create dirs if they are not there (e.g. the "clean" task just ran)
doFirst {
jsBundleDirDebug.mkdirs()
resourcesDirDebug.mkdirs()
} }
// set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
outputs.dir jsBundleDirDebug
outputs.dir resourcesDirDebug
// set up the call to the react-native cli
workingDir reactRoot
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
} else {
commandLine "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
}
enabled config.bundleInDebug ?: false
}
task bundleReleaseJsAndAssets(type: Exec) {
// create dirs if they are not there (e.g. the "clean" task just ran)
doFirst {
jsBundleDirRelease.mkdirs()
resourcesDirRelease.mkdirs()
}
// set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
outputs.dir jsBundleDirRelease
outputs.dir resourcesDirRelease
// set up the call to the react-native cli
workingDir reactRoot
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine "cmd","/c", "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
} else {
commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
}
enabled config.bundleInRelease ?: true
} }
gradle.projectsEvaluated { gradle.projectsEvaluated {
// hook bundleDebugJsAndAssets into the android build process // Grab all build types and product flavors
bundleDebugJsAndAssets.dependsOn mergeDebugResources def buildTypes = android.buildTypes.collect { type -> type.name }
bundleDebugJsAndAssets.dependsOn mergeDebugAssets def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
processDebugResources.dependsOn bundleDebugJsAndAssets
// hook bundleReleaseJsAndAssets into the android build process // When no product flavors defined, use empty
bundleReleaseJsAndAssets.dependsOn mergeReleaseResources if (!productFlavors) productFlavors.add('')
bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
processReleaseResources.dependsOn bundleReleaseJsAndAssets productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
// Create variant and target names
def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}"
def targetPath = productFlavorName ?
"${productFlavorName}/${buildTypeName}" :
"${buildTypeName}"
// React js bundle directories
def jsBundleDirConfigName = "jsBundleDir${targetName}"
def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
file("$buildDir/intermediates/assets/${targetPath}")
def resourcesDirConfigName = "resourcesDir${targetName}"
def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
file("$buildDir/intermediates/res/merged/${targetPath}")
def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
// Bundle task name for variant
def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
def currentBundleTask = tasks.create(
name: bundleJsAndAssetsTaskName,
type: Exec) {
group = "react"
description = "bundle JS and assets for ${targetName}."
// Create dirs if they are not there (e.g. the "clean" task just ran)
doFirst {
jsBundleDir.mkdirs()
resourcesDir.mkdirs()
}
// Set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
outputs.dir jsBundleDir
outputs.dir resourcesDir
// Set up the call to the react-native cli
workingDir reactRoot
// Set up dev mode
def devEnabled = !targetName.toLowerCase().contains("release")
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine "cmd", "/c", "node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
} else {
commandLine "node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
}
enabled config."bundleIn${targetName}" ||
config."bundleIn${buildTypeName.capitalize()}" ?:
targetName.toLowerCase().contains("release")
}
// Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
currentBundleTask.dependsOn("merge${targetName}Resources")
currentBundleTask.dependsOn("merge${targetName}Assets")
runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
runBefore("processX86${targetName}Resources", currentBundleTask)
runBefore("processUniversal${targetName}Resources", currentBundleTask)
runBefore("process${targetName}Resources", currentBundleTask)
}
}
} }

View File

@ -1,12 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testfairy"> package="com.testfairy.react.example">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:label="@string/app_name" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/launcher"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -1,78 +0,0 @@
package com.testfairy;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
private ReactInstanceManager mReactInstanceManager;
private ReactRootView mReactRootView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "TestFairy", null);
setContentView(mReactRootView);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onResume(this, this);
}
}
}

View File

@ -0,0 +1,42 @@
package com.testfairy.react.example;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.testfairy.react.TestFairyPackage;
import java.util.Arrays;
import java.util.List;
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 "TestFairy";
}
/**
* Returns whether dev mode should be enabled.
* This enables e.g. the dev menu.
*/
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new TestFairyPackage()
);
}
}

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -16,5 +16,9 @@ allprojects {
repositories { repositories {
mavenLocal() mavenLocal()
jcenter() jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$projectDir/../../node_modules/react-native/android"
}
} }
} }

View File

@ -1,3 +1,5 @@
rootProject.name = 'TestFairy' rootProject.name = 'TestFairy'
include ':app' include ':app'
include ':react-native-testfairy'
project(':react-native-testfairy').projectDir = new File(settingsDir, '../node_modules/react-native-testfairy/android')

View File

@ -2,24 +2,33 @@
* Sample React Native App * Sample React Native App
* https://github.com/facebook/react-native * https://github.com/facebook/react-native
*/ */
'use strict';
var React = require('react-native'); import React, {
var {
AppRegistry, AppRegistry,
Component,
StyleSheet, StyleSheet,
Text, Text,
View, View
} = React; } from 'react-native';
var TestFairy = React.createClass({ const TestFairyBridge = require('react-native-testfairy');
render: function() {
class TestFairy extends Component {
componentWillMount() {
TestFairyBridge.begin('5b3af35e59a1e074e2d50675b1b629306cf0cfbd');
}
componentDidMount() {
TestFairyBridge.hideView(this.refs.instructions);
}
render() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.welcome}> <Text style={styles.welcome}>
Welcome to React Native! Welcome to React Native!
</Text> </Text>
<Text style={styles.instructions}> <Text style={styles.instructions} ref="instructions">
To get started, edit index.android.js To get started, edit index.android.js
</Text> </Text>
<Text style={styles.instructions}> <Text style={styles.instructions}>
@ -28,9 +37,9 @@ var TestFairy = React.createClass({
</View> </View>
); );
} }
}); }
var styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',

View File

@ -2,43 +2,45 @@
* Sample React Native App * Sample React Native App
* https://github.com/facebook/react-native * https://github.com/facebook/react-native
*/ */
'use strict';
var React = require('react-native'); import React, {
var {
AppRegistry, AppRegistry,
Component,
StyleSheet, StyleSheet,
Text, Text,
View, View
findNodeHandle } from 'react-native';
} = React;
const TestFairyBridge = require('react-native-testfairy'); const TestFairyBridge = require('react-native-testfairy');
var TestFairy = React.createClass({ class TestFairy extends Component {
componentDidMount: function() { componentWillMount() {
TestFairyBridge.hideView(findNodeHandle(this.refs.instructions)); TestFairyBridge.begin('5b3af35e59a1e074e2d50675b1b629306cf0cfbd');
}, }
render: function() { componentDidMount() {
TestFairyBridge.hideView(this.refs.instructions);
}
render() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.welcome}> <Text style={styles.welcome}>
Welcome to React Native! Welcome to React Native!
</Text> </Text>
<Text style={styles.instructions} ref="instructions"> <Text style={styles.instructions}>
To get started, edit index.ios.js To get started, edit index.ios.js
</Text> </Text>
<Text style={styles.instructions}> <Text style={styles.instructions} ref="instructions">
Press Cmd+R to reload,{'\n'} Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu Cmd+D or shake for dev menu
</Text> </Text>
</View> </View>
); );
} }
}); }
var styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
@ -57,5 +59,4 @@ var styles = StyleSheet.create({
}, },
}); });
TestFairyBridge.begin('5b3af35e59a1e074e2d50675b1b629306cf0cfbd');
AppRegistry.registerComponent('TestFairy', () => TestFairy); AppRegistry.registerComponent('TestFairy', () => TestFairy);

175
example/ios/TestFairy.h Normal file
View File

@ -0,0 +1,175 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface TestFairy: NSObject
/**
* Initialize a TestFairy session.
*
* @param appToken Your key as given to you in your TestFairy account
*/
+ (void)begin:(NSString *)appToken;
/**
* Initialize a TestFairy session with options.
*
* @param appToken Your key as given to you in your TestFairy account
* @param options A dictionary of options controlling the current session
*/
+ (void)begin:(NSString *)appToken withOptions:(NSDictionary *)options;
/**
* Change the server endpoint for use with on-premise hosting. Please
* contact support or sales for more information. Must be called before begin
*
* @param serverOverride
*/
+ (void)setServerEndpoint:(NSString *)serverOverride;
/**
* Returns SDK version (x.x.x) string
*
* @return version
*/
+ (NSString *)version;
/**
* Hides a specific view from appearing in the video generated.
*
* @param view The specific view you wish to hide from screenshots
*
*/
+ (void)hideView:(UIView *)view;
/**
* Hides a specific html element from appearing in your UIWebView
*
* @param selector The specific selector you wish to hide from screenshots. Multiple selectors can be comma separated
*/
+ (void)hideWebViewElements:(NSString *)selector;
/**
* Pushes the feedback view controller. Hook a button
* to this method to allow users to provide feedback about the current
* session. All feedback will appear in your build report page, and in
* the recorded session page.
*
*/
+ (void)pushFeedbackController;
/**
* Send a feedback on behalf of the user. Call when using a in-house
* feedback view controller with a custom design and feel. Feedback will
* be associated with the current session.
*
* @param feedbackString Feedback text
*/
+ (void)sendUserFeedback:(NSString *)feedbackString;
/**
* Proxy didUpdateLocation delegate values and these
* locations will appear in the recorded sessions. Useful for debugging
* actual long/lat values against what the user sees on screen.
*
* @param locations Array of CLLocation. The first object of the array will determine the user location
*/
+ (void)updateLocation:(NSArray *)locations;
/**
* Marks a checkpoint in session. Use this text to tag a session
* with a checkpoint name. Later you can filter sessions where your
* user passed through this checkpoint, for bettering understanding
* user experience and behavior.
*
* @param name The checkpoint name
*/
+ (void)checkpoint:(NSString *)name;
/**
* Sets a correlation identifier for this session. This value can
* be looked up via web dashboard. For example, setting correlation
* to the value of the user-id after they logged in. Can be called
* only once per session (subsequent calls will be ignored.)
*
* @param correlationId Id for the current session
*/
+ (void)setCorrelationId:(NSString *)correlationId;
/**
* Sets a correlation identifier for this session. This value can
* be looked up via web dashboard. For example, setting correlation
* to the value of the user-id after they logged in. Can be called
* only once per session (subsequent calls will be ignored.)
*
* @param correlationId Id for the current session
*/
+ (void)identify:(NSString *)correlationId;
/**
* Sets a correlation identifier for this session. This value can
* be looked up via web dashboard. For example, setting correlation
* to the value of the user-id after they logged in. Can be called
* only once per session (subsequent calls will be ignored.)
*
* @param correlationId Id for the current session
* @param traits Attributes and custom attributes to be associated with this session
*/
+ (void)identify:(NSString *)correlationId traits:(NSDictionary *)traits;
/**
* Pauses the current session. This method stops recoding of
* the current session until resume has been called.
*
* @see resume
*/
+ (void)pause;
/**
* Resumes the recording of the current session. This method
* resumes a session after it was paused.
*
* @see pause
*/
+ (void)resume;
/**
* Returns the address of the recorded session on testfairy's
* developer portal. Will return nil if recording not yet started.
*
* @return session URL
*/
+ (NSString *)sessionUrl;
/**
* Takes a screenshot.
*
*/
+ (void)takeScreenshot;
/**
* Remote logging, use TFLog as you would use printf. These logs will be sent to the server,
* but will not appear in the console.
*/
#if __cplusplus
extern "C" {
#endif
void TFLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
void TFLogv(NSString *format, va_list arg_list);
#if __cplusplus
}
#endif
@end
extern NSString *const TFSDKIdentityTraitNameKey;
extern NSString *const TFSDKIdentityTraitEmailAddressKey;
extern NSString *const TFSDKIdentityTraitBirthdayKey;
extern NSString *const TFSDKIdentityTraitGenderKey;
extern NSString *const TFSDKIdentityTraitPhoneNumberKey;
extern NSString *const TFSDKIdentityTraitWebsiteAddressKey;
extern NSString *const TFSDKIdentityTraitAgeKey;
extern NSString *const TFSDKIdentityTraitSignupDateKey;
extern NSString *const TFSDKEnableCrashReporterKey;

View File

@ -21,10 +21,12 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
42E652531C42DD9D008B8114 /* libTestFairy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42E6524E1C42DD9D008B8114 /* libTestFairy.a */; }; 42547DE11CBB43FE007BA376 /* RCTTestFairyBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 42547DDD1CBB43FE007BA376 /* RCTTestFairyBridge.m */; };
42E652541C42DD9D008B8114 /* RCTTestFairyBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E652501C42DD9D008B8114 /* RCTTestFairyBridge.m */; }; 42547DF11CBB4490007BA376 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42547DEE1CBB4490007BA376 /* AVFoundation.framework */; };
42E652551C42DD9D008B8114 /* upload-dsym.sh in Resources */ = {isa = PBXBuildFile; fileRef = 42E652521C42DD9D008B8114 /* upload-dsym.sh */; }; 42547DF21CBB4490007BA376 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42547DEF1CBB4490007BA376 /* CoreMedia.framework */; };
42E652601C42DE19008B8114 /* libTestFairy.a in Resources */ = {isa = PBXBuildFile; fileRef = 42E6524E1C42DD9D008B8114 /* libTestFairy.a */; }; 42547DF31CBB4490007BA376 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42547DF01CBB4490007BA376 /* SystemConfiguration.framework */; };
42547DF71CBB451B007BA376 /* libTestFairy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42547DF41CBB451B007BA376 /* libTestFairy.a */; };
42547DF81CBB451B007BA376 /* upload-dsym.sh in Resources */ = {isa = PBXBuildFile; fileRef = 42547DF61CBB451B007BA376 /* upload-dsym.sh */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -128,11 +130,14 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = TestFairy/Info.plist; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = TestFairy/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = TestFairy/main.m; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = TestFairy/main.m; sourceTree = "<group>"; };
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
42E6524E1C42DD9D008B8114 /* libTestFairy.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libTestFairy.a; sourceTree = "<group>"; }; 42547DDC1CBB43FE007BA376 /* RCTTestFairyBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTTestFairyBridge.h; path = "../node_modules/react-native-testfairy/ios/RCTTestFairyBridge.h"; sourceTree = "<group>"; };
42E6524F1C42DD9D008B8114 /* RCTTestFairyBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTestFairyBridge.h; sourceTree = "<group>"; }; 42547DDD1CBB43FE007BA376 /* RCTTestFairyBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTTestFairyBridge.m; path = "../node_modules/react-native-testfairy/ios/RCTTestFairyBridge.m"; sourceTree = "<group>"; };
42E652501C42DD9D008B8114 /* RCTTestFairyBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTestFairyBridge.m; sourceTree = "<group>"; }; 42547DEE1CBB4490007BA376 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
42E652511C42DD9D008B8114 /* TestFairy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestFairy.h; sourceTree = "<group>"; }; 42547DEF1CBB4490007BA376 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
42E652521C42DD9D008B8114 /* upload-dsym.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "upload-dsym.sh"; sourceTree = "<group>"; }; 42547DF01CBB4490007BA376 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
42547DF41CBB451B007BA376 /* libTestFairy.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libTestFairy.a; sourceTree = "<group>"; };
42547DF51CBB451B007BA376 /* TestFairy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestFairy.h; sourceTree = "<group>"; };
42547DF61CBB451B007BA376 /* upload-dsym.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "upload-dsym.sh"; sourceTree = "<group>"; };
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -149,6 +154,9 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
42547DF11CBB4490007BA376 /* AVFoundation.framework in Frameworks */,
42547DF21CBB4490007BA376 /* CoreMedia.framework in Frameworks */,
42547DF31CBB4490007BA376 /* SystemConfiguration.framework in Frameworks */,
146834051AC3E58100842450 /* libReact.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */,
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
@ -156,10 +164,10 @@
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
42E652531C42DD9D008B8114 /* libTestFairy.a in Frameworks */,
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
42547DF71CBB451B007BA376 /* libTestFairy.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -242,6 +250,7 @@
13B07FAE1A68108700A75B9A /* TestFairy */ = { 13B07FAE1A68108700A75B9A /* TestFairy */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
42547DED1CBB4405007BA376 /* TestFairySDK */,
008F07F21AC5B25A0029DE68 /* main.jsbundle */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */, 13B07FB01A68108700A75B9A /* AppDelegate.m */,
@ -261,16 +270,16 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
42E6524D1C42DD9D008B8114 /* ios */ = { 42547DED1CBB4405007BA376 /* TestFairySDK */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
42E6524E1C42DD9D008B8114 /* libTestFairy.a */, 42547DF41CBB451B007BA376 /* libTestFairy.a */,
42E6524F1C42DD9D008B8114 /* RCTTestFairyBridge.h */, 42547DF51CBB451B007BA376 /* TestFairy.h */,
42E652501C42DD9D008B8114 /* RCTTestFairyBridge.m */, 42547DF61CBB451B007BA376 /* upload-dsym.sh */,
42E652511C42DD9D008B8114 /* TestFairy.h */, 42547DDC1CBB43FE007BA376 /* RCTTestFairyBridge.h */,
42E652521C42DD9D008B8114 /* upload-dsym.sh */, 42547DDD1CBB43FE007BA376 /* RCTTestFairyBridge.m */,
); );
path = ios; name = TestFairySDK;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
78C398B11ACF4ADC00677621 /* Products */ = { 78C398B11ACF4ADC00677621 /* Products */ = {
@ -284,7 +293,6 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = { 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
42E6524D1C42DD9D008B8114 /* ios */,
146833FF1AC3E56700842450 /* React.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */,
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
@ -310,6 +318,9 @@
83CBB9F61A601CBA00E9B192 = { 83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
42547DEE1CBB4490007BA376 /* AVFoundation.framework */,
42547DEF1CBB4490007BA376 /* CoreMedia.framework */,
42547DF01CBB4490007BA376 /* SystemConfiguration.framework */,
13B07FAE1A68108700A75B9A /* TestFairy */, 13B07FAE1A68108700A75B9A /* TestFairy */,
832341AE1AAA6A7D00B99B32 /* Libraries */, 832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* TestFairyTests */, 00E356EF1AD99517003FC87E /* TestFairyTests */,
@ -528,9 +539,8 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
42E652601C42DE19008B8114 /* libTestFairy.a in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
42E652551C42DD9D008B8114 /* upload-dsym.sh in Resources */, 42547DF81CBB451B007BA376 /* upload-dsym.sh in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -550,7 +560,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "../node_modules/react-native/packager/react-native-xcode.sh"; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@ -569,7 +579,7 @@
files = ( files = (
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */,
42E652541C42DD9D008B8114 /* RCTTestFairyBridge.m in Sources */, 42547DE11CBB43FE007BA376 /* RCTTestFairyBridge.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -647,9 +657,10 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/ios", "$(PROJECT_DIR)",
); );
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = com.testfairy.react.Example;
PRODUCT_NAME = TestFairy; PRODUCT_NAME = TestFairy;
}; };
name = Debug; name = Debug;
@ -667,9 +678,10 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/ios", "$(PROJECT_DIR)",
); );
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = com.testfairy.react.Example;
PRODUCT_NAME = TestFairy; PRODUCT_NAME = TestFairy;
}; };
name = Release; name = Release;

View File

@ -36,7 +36,9 @@
/** /**
* OPTION 2 * OPTION 2
* Load from pre-bundled file on disk. The static bundle is automatically * Load from pre-bundled file on disk. The static bundle is automatically
* generated by "Bundle React Native code and images" build step. * generated by the "Bundle React Native code and images" build step when
* running the project on an actual device or running the project on the
* simulator in the "Release" build configuration.
*/ */
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
@ -22,6 +22,13 @@
<string>1</string> <string>1</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key> <key>UIRequiredDeviceCapabilities</key>
@ -36,13 +43,5 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSAppTransportSecurity</key>
<dict>
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict> </dict>
</plist> </plist>

View File

@ -1 +0,0 @@
../../ios/

BIN
example/ios/libTestFairy.a Normal file

Binary file not shown.

View File

@ -0,0 +1,85 @@
#!/bin/sh
TESTFAIRY_ENDPOINT="http://app.testfairy.com/upload/dsym/"
ZIP=zip
CURL=curl
STAT=stat
DATE=date
log() {
NOW=$($DATE +"%Y-%m-%d %H:%M:%S")
echo "${NOW} ${1}"
}
help() {
echo "Usage: ${0} [-f] TESTFAIRY_API_KEY [-p DSYM_PATH]"
exit 1
}
DAEMON=1
if [ "${1}" == "-f" ]; then
DAEMON=0
shift
elif [ "${1}" == "-d" ]; then
# backward compatible when -f was the default
shift
fi
API_KEY="${1}"
if [ ! "${API_KEY}" ]; then
help
fi
DSYM_PATH=${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}
if [ "${#}" -gt 1 ]; then
shift
if [ "${1}" != "-p" ]; then
help
fi
shift
DSYM_PATH="${1}"
fi
if [ "${DSYM_PATH}" == "" ] || [ "${DSYM_PATH}" == "/" ] || [ ! -d "${DSYM_PATH}" ]; then
echo "Fatal: Can't find .dSYM folder!"
help
fi
NOW=$($DATE +%s)
TMP_FILENAME="/tmp/${NOW}-${DWARF_DSYM_FILE_NAME}.zip"
# Compress the .dSYM folder into a zip file
log "Compressing .dSYM folder ${DSYM_PATH}"
$ZIP -qrp9 "${TMP_FILENAME}" "${DSYM_PATH}"
FILE_SIZE=$($STAT -f "%z" "${TMP_FILENAME}")
foreground_upload() {
# Upload zipped .dSYM file to TestFairy's servers
STARTED=$($DATE +"%s")
$CURL -s -F api_key="${API_KEY}" -F dsym=@"${1}" -o /dev/null "${TESTFAIRY_ENDPOINT}"
ENDED=$($DATE +"%s")
DIFF=$(expr ${ENDED} - ${STARTED})
log "Symbols uploaded in ${DIFF} seconds"
# Clean up behind
rm -f ${TMP_FILENAME}
}
background_upload() {
sh -c "$CURL -F api_key=\"${API_KEY}\" -F dsym=@\"${1}\" -s -o /dev/null \"${TESTFAIRY_ENDPOINT}\"; rm -f ${TMP_FILENAME};" /dev/null 2>&1 &
}
if [ "$DAEMON" == "0" ]; then
log "Uploading ${FILE_SIZE} bytes to dsym server in foreground"
foreground_upload "${TMP_FILENAME}"
else
log "Uploading ${FILE_SIZE} bytes to dsym server in background"
background_upload "${TMP_FILENAME}"
fi
log "TestFairy .dSYM upload script ends"

View File

@ -6,7 +6,8 @@
"start": "node node_modules/react-native/local-cli/cli.js start" "start": "node node_modules/react-native/local-cli/cli.js start"
}, },
"dependencies": { "dependencies": {
"react-native": "^0.17.0", "react": "^0.14.8",
"react-native": "^0.23.1",
"react-native-testfairy": "file:../" "react-native-testfairy": "file:../"
} }
} }

View File

@ -1,6 +1,8 @@
'use strict'; 'use strict';
const TestFairyBridge = require("react-native").NativeModules.TestFairyBridge; var React = require('react-native');
const findNodeHandle = React.findNodeHandle;
const TestFairyBridge = React.NativeModules.TestFairyBridge;
class TestFairy { class TestFairy {
/** /**
@ -94,7 +96,7 @@ class TestFairy {
* @param view The specific view you wish to hide from screenshots * @param view The specific view you wish to hide from screenshots
*/ */
static hideView(viewTag) { static hideView(viewTag) {
TestFairyBridge.hideView(viewTag); TestFairyBridge.hideView(findNodeHandle(viewTag));
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "react-native-testfairy", "name": "react-native-testfairy",
"version": "1.6.6", "version": "2.0.0",
"description": "TestFairy for React Native", "description": "TestFairy for React Native",
"author": "Gil Megidish", "author": "Gil Megidish",
"main": "./index.js", "main": "./index.js",
@ -15,7 +15,8 @@
"react-component", "react-component",
"testfairy", "testfairy",
"react-native", "react-native",
"ios" "ios",
"android"
], ],
"author": "testfairy", "author": "testfairy",
"license": "Apache-2.0", "license": "Apache-2.0",