├── .nvmrc
├── .watchmanconfig
├── android
├── settings.gradle
├── app
│ ├── src
│ │ └── main
│ │ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ └── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── com
│ │ │ └── multiplatformreact
│ │ │ └── MainActivity.java
│ ├── proguard-rules.pro
│ ├── react.gradle
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── build.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
├── readme
├── move-things.png
└── initial-project.png
├── src
└── components
│ └── root
│ ├── root-render.ios.js
│ ├── root-render.android.js
│ ├── root-render.js
│ ├── root.js
│ └── root-render.native.js
├── index.js
├── rn-cli.config.js
├── index.ios.js
├── index.android.js
├── ios
├── MultiPlatformReact
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── AppDelegate.m
│ └── Base.lproj
│ │ └── LaunchScreen.xib
├── MultiPlatformReactTests
│ ├── Info.plist
│ └── MultiPlatformReactTests.m
└── MultiPlatformReact.xcodeproj
│ ├── xcshareddata
│ └── xcschemes
│ │ └── MultiPlatformReact.xcscheme
│ └── project.pbxproj
├── webpack.config.js
├── web
└── index.html
├── electron
└── index.electron.js
├── .eslintrc
├── LICENSE
├── .gitignore
├── package.json
├── .flowconfig
└── README.md
/.nvmrc:
--------------------------------------------------------------------------------
1 | 5.2.0
2 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'MultiPlatformReact'
2 |
3 | include ':app'
4 |
--------------------------------------------------------------------------------
/readme/move-things.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/readme/move-things.png
--------------------------------------------------------------------------------
/readme/initial-project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/readme/initial-project.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiPlatformReact
3 |
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gfogle/multi-platform-react/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/components/root/root-render.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import Render from './root-render.native';
4 |
5 | export default function () {
6 | return Render.call(this, this.props, this.state);
7 | }
8 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Root from './src/components/root/root';
4 |
5 | ReactDOM.render(
6 | ,
7 | document.getElementById('root')
8 | );
9 |
--------------------------------------------------------------------------------
/src/components/root/root-render.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import Render from './root-render.native';
4 |
5 | export default function () {
6 | return Render.call(this, this.props, this.state);
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/root/root-render.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 |
5 | export default function () {
6 | return (
7 |
8 |
Hello World
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/rn-cli.config.js:
--------------------------------------------------------------------------------
1 | var blacklist = require('react-native/packager/blacklist');
2 |
3 | var config = {
4 | getBlacklistRE(platform) {
5 | return blacklist(platform, [
6 | /web/
7 | ]);
8 | }
9 | };
10 |
11 | module.exports = config;
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
6 |
--------------------------------------------------------------------------------
/src/components/root/root.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import Render from './root-render';
4 |
5 | import { Component } from 'react';
6 |
7 | export default class Root extends Component {
8 | render () {
9 | return Render.call(this, this.props, this.state);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/index.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // it is important to import the react package before anything else
4 | import React from 'react';
5 | import {
6 | AppRegistry
7 | } from 'react-native';
8 |
9 | import Root from './src/components/root/root';
10 |
11 | AppRegistry.registerComponent('MultiPlatformReact', () => Root);
12 |
--------------------------------------------------------------------------------
/index.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // it is important to import the react package before anything else
4 | import React from 'react';
5 | import {
6 | AppRegistry
7 | } from 'react-native';
8 |
9 | import Root from './src/components/root/root';
10 |
11 | AppRegistry.registerComponent('MultiPlatformReact', () => Root);
12 |
--------------------------------------------------------------------------------
/src/components/root/root-render.native.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React, {
4 | StyleSheet,
5 | View,
6 | Text
7 | } from 'react-native';
8 |
9 | export default function () {
10 | return (
11 |
12 | Hello World
13 |
14 | );
15 | }
16 |
17 | var styles = StyleSheet.create({
18 | container: {
19 | flex: 1,
20 | flexDirection: "column",
21 | justifyContent: "center",
22 | backgroundColor: "#303030"
23 | }
24 | });
25 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | jcenter()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: './index.js',
6 | output: {
7 | path: './web',
8 | filename: 'bundle.js'
9 | },
10 | module: {
11 | loaders: [
12 | {
13 | test: /.js?$/,
14 | loader: 'babel',
15 | exclude: /node_modules/,
16 | query:
17 | {
18 | presets:['es2015','react']
19 | }
20 | }
21 | ]
22 | },
23 | debug: true,
24 | devtool: "source-map",
25 | plugins: [
26 | new webpack.DefinePlugin({
27 | __DEV__: process.env.NODE_ENV === "development"
28 | })
29 | ]
30 | };
31 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MultiPlatformReact
6 |
7 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/electron/index.electron.js:
--------------------------------------------------------------------------------
1 | // control application life
2 | const electron = require('electron');
3 | const app = electron.app;
4 | const BrowserWindow = electron.BrowserWindow;
5 |
6 | var mainWindow = null;
7 |
8 | // quit when all windows are closed
9 | app.on("window-all-closed", function() {
10 | if (process.platform !== "darwin") {
11 | app.quit();
12 | }
13 | });
14 |
15 | // Electron is ready and can create browser windows
16 | app.on("ready", function() {
17 | mainWindow = new BrowserWindow({width: 800, height: 600});
18 | mainWindow.loadURL("file://" + __dirname + "/../web/index.html");
19 | mainWindow.webContents.openDevTools();
20 |
21 | mainWindow.on("closed", function() {
22 | mainWindow = null;
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/ios/MultiPlatformReactTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "browser": true
5 | },
6 | "globals": {
7 | "i18n": true,
8 | "React": true,
9 | "ReactDOM": true,
10 | "require": true
11 | },
12 | "rules": {
13 | "no-console": 2,
14 | "default-case": 2,
15 | "indent": [2, "tab"],
16 | "new-cap": 0,
17 | "no-catch-shadow": 2,
18 | "no-eq-null": 2,
19 | "no-floating-decimal": 2,
20 | "no-inline-comments": 0,
21 | "no-nested-ternary": 2,
22 | "no-param-reassign": 0,
23 | "quote-props": [2, "as-needed", {"keywords": true, "unnecessary": false}],
24 | "no-self-compare": 2,
25 | "no-shadow": 0,
26 | "no-throw-literal": 2,
27 | "no-undefined": 0,
28 | "no-void": 2,
29 | "semi": 2,
30 | "space-after-keywords": 2,
31 | "wrap-iife": [2, "outside"],
32 | "dot-notation": 0
33 | },
34 | "ecmaFeatures": {
35 | "jsx": true,
36 | "modules": true
37 | },
38 | "plugins": [
39 | "eslint-plugin-react"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 George Fogle
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/multiplatformreact/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.multiplatformreact;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.shell.MainReactPackage;
6 |
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | public class MainActivity extends ReactActivity {
11 |
12 | /**
13 | * Returns the name of the main component registered from JavaScript.
14 | * This is used to schedule rendering of the component.
15 | */
16 | @Override
17 | protected String getMainComponentName() {
18 | return "MultiPlatformReact";
19 | }
20 |
21 | /**
22 | * Returns whether dev mode should be enabled.
23 | * This enables e.g. the dev menu.
24 | */
25 | @Override
26 | protected boolean getUseDeveloperSupport() {
27 | return BuildConfig.DEBUG;
28 | }
29 |
30 | /**
31 | * A list of packages used by the app. If the app uses additional views
32 | * or modules besides the default ones, add more packages here.
33 | */
34 | @Override
35 | protected List getPackages() {
36 | return Arrays.asList(
37 | new MainReactPackage()
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | node_modules
28 |
29 | # Optional npm cache directory
30 | .npm
31 |
32 | # Optional REPL history
33 | .node_repl_history
34 |
35 | # environment vars
36 | .env
37 |
38 | # OSX
39 | #
40 | .DS_Store
41 | ios/main.jsbundle
42 |
43 | # Xcode
44 | #
45 | build/
46 | *.pbxuser
47 | !default.pbxuser
48 | *.mode1v3
49 | !default.mode1v3
50 | *.mode2v3
51 | !default.mode2v3
52 | *.perspectivev3
53 | !default.perspectivev3
54 | xcuserdata
55 | *.xccheckout
56 | *.moved-aside
57 | DerivedData
58 | *.hmap
59 | *.ipa
60 | *.xcuserstate
61 | project.xcworkspace
62 |
63 | # Android/IJ
64 | #
65 | .idea
66 | .gradle
67 | local.properties
68 |
69 | # webstorm
70 | .idea
71 |
72 | # distribution of web
73 | dist
74 | web/bundle.js
75 | web/bundle.js.map
76 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSAllowsArbitraryLoads
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multi-platform-react",
3 | "version": "1.0.0",
4 | "description": "react on: web, ios, android, electron",
5 | "main": "index.js",
6 | "scripts": {
7 | "start:electron": "node_modules/.bin/electron electron/index.electron.js",
8 | "start:ios": "node_modules/react-native/packager/packager.sh",
9 | "start:web": "NODE_ENV=development node_modules/.bin/webpack-dev-server --progress --colors --content-base web/",
10 | "start:android": "node_modules/react-native run-android",
11 | "build:web": "NODE_ENV=production node_modules/.bin/webpack -p",
12 | "build:ios": "react-native bundle --entry-file index.ios.js --bundle-output ios/main.jsbundle --platform ios --dev false",
13 | "build:android": "node_modules/react-native bundle --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --platform android --dev false"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/gfogle/multi-platform-react.git"
18 | },
19 | "keywords": [
20 | "react",
21 | "react",
22 | "native",
23 | "electron",
24 | "webpack"
25 | ],
26 | "author": "George Fogle",
27 | "license": "MIT",
28 | "bugs": {
29 | "url": "https://github.com/gfogle/multi-platform-react/issues"
30 | },
31 | "homepage": "https://github.com/gfogle/multi-platform-react#readme",
32 | "dependencies": {
33 | "react": "^0.14.7",
34 | "react-dom": "^0.14.7",
35 | "react-native": "^0.19.0"
36 | },
37 | "devDependencies": {
38 | "babel-core": "^6.4.5",
39 | "babel-loader": "^6.2.1",
40 | "babel-preset-es2015": "^6.3.13",
41 | "babel-preset-react": "^6.3.13",
42 | "electron-prebuilt": "^0.36.5",
43 | "eslint-plugin-react": "^3.16.1",
44 | "webpack": "^1.12.12",
45 | "webpack-dev-server": "^1.14.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | # We fork some components by platform.
4 | .*/*.web.js
5 | .*/*.android.js
6 |
7 | # Some modules have their own node_modules with overlap
8 | .*/node_modules/node-haste/.*
9 |
10 | # Ugh
11 | .*/node_modules/babel.*
12 | .*/node_modules/babylon.*
13 | .*/node_modules/invariant.*
14 |
15 | # Ignore react and fbjs where there are overlaps, but don't ignore
16 | # anything that react-native relies on
17 | .*/node_modules/fbjs/lib/Map.js
18 | .*/node_modules/fbjs/lib/Promise.js
19 | .*/node_modules/fbjs/lib/fetch.js
20 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js
21 | .*/node_modules/fbjs/lib/isEmpty.js
22 | .*/node_modules/fbjs/lib/crc32.js
23 | .*/node_modules/fbjs/lib/ErrorUtils.js
24 |
25 | # Flow has a built-in definition for the 'react' module which we prefer to use
26 | # over the currently-untyped source
27 | .*/node_modules/react/react.js
28 | .*/node_modules/react/lib/React.js
29 | .*/node_modules/react/lib/ReactDOM.js
30 |
31 | # Ignore commoner tests
32 | .*/node_modules/commoner/test/.*
33 |
34 | # See https://github.com/facebook/flow/issues/442
35 | .*/react-tools/node_modules/commoner/lib/reader.js
36 |
37 | # Ignore jest
38 | .*/node_modules/jest-cli/.*
39 |
40 | # Ignore Website
41 | .*/website/.*
42 |
43 | [include]
44 |
45 | [libs]
46 | node_modules/react-native/Libraries/react-native/react-native-interface.js
47 |
48 | [options]
49 | module.system=haste
50 |
51 | munge_underscores=true
52 |
53 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
54 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub'
55 |
56 | suppress_type=$FlowIssue
57 | suppress_type=$FlowFixMe
58 | suppress_type=$FixMe
59 |
60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
61 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
62 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
63 |
64 | [version]
65 | 0.20.1
66 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import "RCTRootView.h"
13 |
14 | @implementation AppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 | {
18 | NSURL *jsCodeLocation;
19 |
20 | /**
21 | * Loading JavaScript code - uncomment the one you want.
22 | *
23 | * OPTION 1
24 | * Load from development server. Start the server from the repository root:
25 | *
26 | * $ npm start
27 | *
28 | * To run on device, change `localhost` to the IP address of your computer
29 | * (you can get this by typing `ifconfig` into the terminal and selecting the
30 | * `inet` value under `en0:`) and make sure your computer and iOS device are
31 | * on the same Wi-Fi network.
32 | */
33 |
34 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
35 |
36 | /**
37 | * OPTION 2
38 | * Load from pre-bundled file on disk. The static bundle is automatically
39 | * generated by "Bundle React Native code and images" build step.
40 | */
41 |
42 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
43 |
44 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
45 | moduleName:@"MultiPlatformReact"
46 | initialProperties:nil
47 | launchOptions:launchOptions];
48 |
49 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
50 | UIViewController *rootViewController = [UIViewController new];
51 | rootViewController.view = rootView;
52 | self.window.rootViewController = rootViewController;
53 | [self.window makeKeyAndVisible];
54 | return YES;
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReactTests/MultiPlatformReactTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import "RCTLog.h"
14 | #import "RCTRootView.h"
15 |
16 | #define TIMEOUT_SECONDS 240
17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
18 |
19 | @interface MultiPlatformReactTests : XCTestCase
20 |
21 | @end
22 |
23 | @implementation MultiPlatformReactTests
24 |
25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
26 | {
27 | if (test(view)) {
28 | return YES;
29 | }
30 | for (UIView *subview in [view subviews]) {
31 | if ([self findSubviewInView:subview matching:test]) {
32 | return YES;
33 | }
34 | }
35 | return NO;
36 | }
37 |
38 | - (void)testRendersWelcomeScreen
39 | {
40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
42 | BOOL foundElement = NO;
43 |
44 | __block NSString *redboxError = nil;
45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
46 | if (level >= RCTLogLevelError) {
47 | redboxError = message;
48 | }
49 | });
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | RCTSetLogFunction(RCTDefaultLogFunction);
64 |
65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
67 | }
68 |
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 |
30 | # Do not strip any method/class that is annotated with @DoNotStrip
31 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
32 | -keepclassmembers class * {
33 | @com.facebook.proguard.annotations.DoNotStrip *;
34 | }
35 |
36 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
37 | void set*(***);
38 | *** get*();
39 | }
40 |
41 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
42 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
43 | -keepclassmembers,includedescriptorclasses class * { native ; }
44 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
45 | -keepclassmembers class * { @com.facebook.react.uimanager.ReactProp ; }
46 | -keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup ; }
47 |
48 | -dontwarn com.facebook.react.**
49 |
50 | # okhttp
51 |
52 | -keepattributes Signature
53 | -keepattributes *Annotation*
54 | -keep class com.squareup.okhttp.** { *; }
55 | -keep interface com.squareup.okhttp.** { *; }
56 | -dontwarn com.squareup.okhttp.**
57 |
58 | # okio
59 |
60 | -keep class sun.misc.Unsafe { *; }
61 | -dontwarn java.nio.file.*
62 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
63 | -dontwarn okio.**
64 |
65 | # stetho
66 |
67 | -dontwarn com.facebook.stetho.**
68 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/android/app/react.gradle:
--------------------------------------------------------------------------------
1 | import org.apache.tools.ant.taskdefs.condition.Os
2 |
3 | def config = project.hasProperty("react") ? project.react : [];
4 |
5 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
6 | def entryFile = config.entryFile ?: "index.android.js"
7 |
8 | // because elvis operator
9 | def elvisFile(thing) {
10 | return thing ? file(thing) : null;
11 | }
12 |
13 | def reactRoot = elvisFile(config.root) ?: file("../../")
14 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
15 |
16 | void runBefore(String dependentTaskName, Task task) {
17 | Task dependentTask = tasks.findByPath(dependentTaskName);
18 | if (dependentTask != null) {
19 | dependentTask.dependsOn task
20 | }
21 | }
22 |
23 | gradle.projectsEvaluated {
24 | // Grab all build types and product flavors
25 | def buildTypes = android.buildTypes.collect { type -> type.name }
26 | def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
27 |
28 | // When no product flavors defined, use empty
29 | if (!productFlavors) productFlavors.add('')
30 |
31 | productFlavors.each { productFlavorName ->
32 | buildTypes.each { buildTypeName ->
33 | // Create variant and source names
34 | def sourceName = "${buildTypeName}"
35 | def targetName = "${sourceName.capitalize()}"
36 | if (productFlavorName) {
37 | sourceName = "${productFlavorName}${targetName}"
38 | }
39 |
40 | // React js bundle directories
41 | def jsBundleDirConfigName = "jsBundleDir${targetName}"
42 | def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
43 | file("$buildDir/intermediates/assets/${sourceName}")
44 |
45 | def resourcesDirConfigName = "jsBundleDir${targetName}"
46 | def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
47 | file("$buildDir/intermediates/res/merged/${sourceName}")
48 | def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
49 |
50 | // Bundle task name for variant
51 | def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
52 |
53 | def currentBundleTask = tasks.create(
54 | name: bundleJsAndAssetsTaskName,
55 | type: Exec) {
56 | group = "react"
57 | description = "bundle JS and assets for ${targetName}."
58 |
59 | // Create dirs if they are not there (e.g. the "clean" task just ran)
60 | doFirst {
61 | jsBundleDir.mkdirs()
62 | resourcesDir.mkdirs()
63 | }
64 |
65 | // Set up inputs and outputs so gradle can cache the result
66 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
67 | outputs.dir jsBundleDir
68 | outputs.dir resourcesDir
69 |
70 | // Set up the call to the react-native cli
71 | workingDir reactRoot
72 |
73 | // Set up dev mode
74 | def devEnabled = !targetName.toLowerCase().contains("release")
75 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
76 | commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
77 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
78 | } else {
79 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
80 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
81 | }
82 |
83 | enabled config."bundleIn${targetName}" ?: targetName.toLowerCase().contains("release")
84 | }
85 |
86 | // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
87 | currentBundleTask.dependsOn("merge${targetName}Resources")
88 | currentBundleTask.dependsOn("merge${targetName}Assets")
89 |
90 | runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
91 | runBefore("processX86${targetName}Resources", currentBundleTask)
92 | runBefore("processUniversal${targetName}Resources", currentBundleTask)
93 | runBefore("process${targetName}Resources", currentBundleTask)
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/ios/MultiPlatformReact.xcodeproj/xcshareddata/xcschemes/MultiPlatformReact.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
75 |
77 |
83 |
84 |
85 |
86 |
87 |
88 |
94 |
96 |
102 |
103 |
104 |
105 |
107 |
108 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property is in the format 'bundleIn${productFlavor}${buildType}'
30 | * // bundleInFreeDebug: true,
31 | * // bundleInPaidRelease: true,
32 | * // bundleInBeta: true,
33 | *
34 | * // the root of your project, i.e. where "package.json" lives
35 | * root: "../../",
36 | *
37 | * // where to put the JS bundle asset in debug mode
38 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
39 | *
40 | * // where to put the JS bundle asset in release mode
41 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
42 | *
43 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
44 | * // require('./image.png')), in debug mode
45 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
46 | *
47 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
48 | * // require('./image.png')), in release mode
49 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
50 | *
51 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
52 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
53 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
54 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
55 | * // for example, you might want to remove it from here.
56 | * inputExcludes: ["android/**", "ios/**"]
57 | * ]
58 | */
59 |
60 | apply from: "react.gradle"
61 |
62 | /**
63 | * Set this to true to create two separate APKs instead of one:
64 | * - An APK that only works on ARM devices
65 | * - An APK that only works on x86 devices
66 | * The advantage is the size of the APK is reduced by about 4MB.
67 | * Upload all the APKs to the Play Store and people will download
68 | * the correct one based on the CPU architecture of their device.
69 | */
70 | def enableSeparateBuildPerCPUArchitecture = false
71 |
72 | /**
73 | * Run Proguard to shrink the Java bytecode in release builds.
74 | */
75 | def enableProguardInReleaseBuilds = true
76 |
77 | android {
78 | compileSdkVersion 23
79 | buildToolsVersion "23.0.1"
80 |
81 | defaultConfig {
82 | applicationId "com.multiplatformreact"
83 | minSdkVersion 16
84 | targetSdkVersion 22
85 | versionCode 1
86 | versionName "1.0"
87 | ndk {
88 | abiFilters "armeabi-v7a", "x86"
89 | }
90 | }
91 | splits {
92 | abi {
93 | enable enableSeparateBuildPerCPUArchitecture
94 | universalApk false // Also generate an universal APK
95 | reset()
96 | include "armeabi-v7a", "x86"
97 | }
98 | }
99 | buildTypes {
100 | release {
101 | minifyEnabled enableProguardInReleaseBuilds
102 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
103 | }
104 | }
105 | // applicationVariants are e.g. debug, release
106 | applicationVariants.all { variant ->
107 | variant.outputs.each { output ->
108 | // For each separate APK per architecture, set a unique version code as described here:
109 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
110 | def versionCodes = ["armeabi-v7a":1, "x86":2]
111 | def abi = output.getFilter(OutputFile.ABI)
112 | if (abi != null) { // null for the universal-debug, universal-release variants
113 | output.versionCodeOverride =
114 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
115 | }
116 | }
117 | }
118 | }
119 |
120 | dependencies {
121 | compile fileTree(dir: "libs", include: ["*.jar"])
122 | compile "com.android.support:appcompat-v7:23.0.1"
123 | compile "com.facebook.react:react-native:0.19.+"
124 | }
125 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # multi-platform-react
3 |
4 | Sharing of React code across Web, iOS, Android, Electron as Hello World example.
5 | Before you read on, just a quick shout out that there are a lot of web resources
6 | I used to build this out; I'm not a savant. I'll go back through my browser
7 | history at some point, its a scary place to be, and add shout outs.
8 |
9 | ## FOLDER STRUCTURE
10 |
11 | ### React Native init
12 |
13 | Repo was created using `react-native init MultiPlatformReact` which initially
14 | created a folder named the same in the root project. In addition, this uses
15 | eslint so there was an addition `npm install --save-dev eslint-plugin-react`
16 | command run. The initial structure looked like:
17 |
18 | 
19 |
20 | ### Moving things around
21 |
22 | To make the project a little easier to navigate (I hope). Ideally, the specific
23 | index files would be in their respective folders but there are issues where parts
24 | of the project expect them in the root, so they're all there for consistency.
25 | The files now reside at the following:
26 |
27 | 
28 |
29 | ### Shared Components
30 |
31 | The goal of these components are that, to extent you can, keep react-native
32 | in the native files and react in the plain `.js` files. There's only a root
33 | component that imports a `root-render` function. The web / electron files
34 | pickup the standard `root-render.js` file. So each component built is going to
35 | have 5 files. The root component has:
36 |
37 | ```
38 | - root-render.android.js
39 | - root-render.ios.js
40 | - root-render.js
41 | - root-render.native.js
42 | - root.js
43 | ```
44 |
45 | The base root file will pull in `root-render.js` and looks like:
46 |
47 | ```javascript
48 | 'use strict';
49 |
50 | import Render from './root-render';
51 |
52 | import { Component } from 'react';
53 |
54 | export default class Root extends Component {
55 | render () {
56 | return Render.call(this, this.props, this.state);
57 | }
58 | }
59 | ```
60 |
61 | but the iOS and Android platforms will look for the specific `root-render.ios.js`
62 | and `root-render.android.js` files, based on the platform, and both of those look like:
63 |
64 | ```javascript
65 | 'use strict';
66 |
67 | import Render from './root-render.native';
68 |
69 | export default function () {
70 | return Render.call(this, this.props, this.state);
71 | }
72 | ```
73 |
74 | and redirect to the `root-render.native.js` file and look like:
75 |
76 | ```javascript
77 | 'use strict';
78 |
79 | import React, {
80 | StyleSheet,
81 | View,
82 | Text
83 | } from 'react-native';
84 |
85 | export default function () {
86 | return (
87 |
88 | Hello World
89 |
90 | );
91 | }
92 |
93 | var styles = StyleSheet.create({
94 | container: {
95 | flex: 1,
96 | flexDirection: "column",
97 | justifyContent: "center",
98 | backgroundColor: "#303030"
99 | }
100 | });
101 | ```
102 |
103 | ### Web and [ELECTRON](http://electron.atom.io/)
104 |
105 | Each of the web and electron, which uses the web code, have their own file for
106 | the `index.html` and `index.electron.js` files. Webpack is the build system for
107 | web code and will output its bundle files to the web folder. In order to not
108 | cause issues with react native, we need to add an `rn-cli.config.js` file to
109 | blacklist the web folder for weird duplicate entry / dependency errors. Pretty
110 | simple:
111 |
112 | ```javascript
113 | var blacklist = require('react-native/packager/blacklist');
114 |
115 | var config = {
116 | getBlacklistRE(platform) {
117 | return blacklist(platform, [
118 | /web/
119 | ]);
120 | }
121 | };
122 |
123 | module.exports = config;
124 | ```
125 |
126 | When trying to run the electron version, make sure to run the webpack build to
127 | write the bundle.js file to the folder for electron to pickup. The webpack
128 | dev server doesn't currently do that with this configuration.
129 |
130 | ## [WEBPACK](http://webpack.github.io/)
131 |
132 | The project uses webpack for bundling the web code and webpack-dev-server for
133 | basic hosting of the app locally. This is because the project I started this for
134 | is a static hosted app on Amazon S3 so I don't need a server in production.
135 | The config will be found by webpack automatically based on its name and looks like:
136 |
137 | ```javascript
138 | var path = require('path');
139 | var webpack = require('webpack');
140 |
141 | module.exports = {
142 | entry: './index.js',
143 | output: {
144 | path: './web',
145 | filename: 'bundle.js'
146 | },
147 | module: {
148 | loaders: [
149 | {
150 | test: /.js?$/,
151 | loader: 'babel',
152 | exclude: /node_modules/,
153 | query:
154 | {
155 | presets:['es2015','react']
156 | }
157 | }
158 | ]
159 | },
160 | debug: true,
161 | devtool: "source-map",
162 | plugins: [
163 | new webpack.DefinePlugin({
164 | __DEV__: process.env.NODE_ENV === "development"
165 | })
166 | ]
167 | };
168 | ```
169 |
170 | The webpack config is pretty basic but does inject a nice `__DEV__` variable
171 | that you can use to hide things in development you don't quite want in prod such
172 | as, say in a component's render function you wanted to hide a