├── .gitignore ├── .npmignore ├── .prettierrc ├── LICENSE ├── README.md ├── babel.config.js ├── demo └── images │ ├── cluster-expand.gif │ ├── custom-marker.png │ ├── nested-cluster-expand.gif │ ├── zoom-in.gif │ └── zoom-out.gif ├── example ├── App.tsx ├── __tests__ │ └── App-test.tsx ├── android │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── Podfile │ ├── example-tvOS │ │ └── Info.plist │ ├── example-tvOSTests │ │ └── Info.plist │ ├── example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ ├── example.xcworkspace │ │ └── contents.xcworkspacedata │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── metro.config.js └── package.json ├── jest.config.js ├── package.json ├── rollup.config.js ├── src ├── cluster-map.tsx ├── cluster-marker.tsx ├── cluster-service.ts ├── index.ts ├── spec │ ├── cluster-service.test.ts │ ├── mock.constants.ts │ ├── mock.utils.ts │ └── utils.test.tsx ├── typings.ts └── utils.ts ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | .rpt2_cache 4 | 5 | package-lock.json 6 | yarn.lock 7 | yarn-error.log 8 | 9 | # OSX 10 | # 11 | .DS_Store 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | # Android/IntelliJ 34 | # 35 | build/ 36 | .idea 37 | .gradle 38 | local.properties 39 | *.iml 40 | 41 | # Visual Studio Code 42 | # 43 | .vscode/ 44 | 45 | # node.js 46 | # 47 | node_modules/ 48 | npm-debug.log 49 | yarn-error.log 50 | 51 | # BUCK 52 | buck-out/ 53 | \.buckd/ 54 | *.keystore 55 | 56 | # fastlane 57 | # 58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 59 | # screenshots whenever they are needed. 60 | # For more information about the recommended setup visit: 61 | # https://docs.fastlane.tools/best-practices/source-control/ 62 | 63 | */fastlane/report.xml 64 | */fastlane/Preview.html 65 | */fastlane/screenshots 66 | 67 | # Bundle artifact 68 | *.jsbundle 69 | 70 | # CocoaPods 71 | example/ios/Pods/ 72 | example/ios/Podfile.lock -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .prettierrc 2 | rollup.config.json 3 | tsconfig.json 4 | tslint.json 5 | package-lock.json 6 | yarn.lock 7 | yarn-error.log 8 | 9 | .gitignore 10 | src 11 | node_modules 12 | .rpt2_cache 13 | 14 | example/node_modules 15 | example/ios/build 16 | example/ios/Pods 17 | example/ios/Podfile.lock 18 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "semi": true, 5 | "singleQuote": true, 6 | "jsxSingleQuote": false, 7 | "bracketSpacing": true, 8 | "jsxBracketSameLine": false, 9 | "arrowParens": "always", 10 | "trailingComma": "es5", 11 | "endOfLine": "lf", 12 | "printWidth": 80 13 | } 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Codempire 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-cluster-map 2 | 3 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 4 | [![Version](https://img.shields.io/npm/v/react-native-cluster-map.svg)](https://www.npmjs.com/package/react-native-cluster-map) 5 | [![npm](https://img.shields.io/npm/dt/react-native-cluster-map.svg)](https://www.npmjs.com/package/react-native-cluster-map) 6 | [![Email](https://img.shields.io/badge/contact-CODEMPIRE-blue.svg?style=flat)](mailto:sales@codempire.io) 7 | 8 | React Native MapView clustering component for iOS + Android 9 | 10 | --- 11 | 12 | Made by [CODEMPIRE](http://codempire.io/) 13 | 14 | ## Examples 15 | 16 | | Zoom in | Zoom out | 17 | | --------------------------------------------------------- | ----------------------------------------------------------------------- | 18 | | ![Example zoom out](demo/images/zoom-in.gif) | ![Example zoom in](demo/images/zoom-out.gif) | 19 | | **Cluster Expand** | **Nested Cluster Expand** | 20 | | ![Example cluster expand](demo/images/cluster-expand.gif) | ![Example nested cluster expand](demo/images/nested-cluster-expand.gif) | 21 | 22 | ## Installation 23 | 24 | 1. Install [`react-native-maps`](https://github.com/react-native-community/react-native-maps/blob/master/docs/installation.md) 25 | 26 | 2. Install this component 27 | 28 | ```bash 29 | npm install --save react-native-cluster-map 30 | ``` 31 | 32 | ## Usage 33 | 34 | ```javascript 35 | import { Marker } from 'react-native-maps'; 36 | import { ClusterMap } from 'react-native-cluster-map'; 37 | 38 | 46 | 47 | 48 | 49 | ; 50 | ``` 51 | 52 | ### Custom Cluster Marker 53 | 54 | You can customize cluster marker with **renderClusterMarker** prop 55 | 56 | > _MyMap.jsx_ 57 | 58 | ```javascript 59 | import { Marker } from "react-native-maps"; 60 | import { MyCluster } from "./MyCluster"; 61 | 62 | // ... 63 | 64 | renderCustomClusterMarker = (count) => 65 | 66 | render () { 67 | const { markers, region } = this.state; 68 | return ( 69 | 73 | {markers.map((marker) => ( 74 | 75 | ))} 76 | 77 | ) 78 | } 79 | 80 | ``` 81 | 82 | > _MyCluster.jsx_ 83 | 84 | ```javascript 85 | import * as React from 'react'; 86 | import { View, Text, StyleSheet } from 'react-native'; 87 | 88 | export const MyCluster = (props) => { 89 | const { count } = props; 90 | return ( 91 | 92 | {count} 93 | 94 | ); 95 | }; 96 | 97 | const styles = StyleSheet.create({ 98 | width: 50, 99 | height: 50, 100 | borderRadius: 25, 101 | backgroundColor: 'red', 102 | justifyContent: 'center', 103 | alignItems: 'center', 104 | }); 105 | ``` 106 | 107 | ### Result 108 | 109 | ![Custom Marker Example](demo/images/custom-marker.png) 110 | 111 | ## Props 112 | 113 | | Props | Type | Default value | Note | 114 | | ------------------------ | ------------ | ----------------------------------------------------- | ---------------------------------------- | 115 | | **superClusterOptions** | _Options_ | { radius: 16, maxZoom: 15, minZoom: 1, nodeSize: 16 } | SuperCluster lib options | 116 | | **isClusterExpandClick** | _boolean_ | true | Enables cluster zoom on click | 117 | | **region** | _Region_ | **_required_** | Google Map Region | 118 | | **priorityMarker** | _ReactNode_ | null | Marker which will be outside of clusters | 119 | | **renderClusterMarker** | (_object_):ReactNode | undefined | Returns cluster marker component | 120 | | **clusterMarkerProps** | _object_ | undefined | Additional ClusterMarker props | 121 | | **provider** | _'google'_ or _null_ | 'google' | Map provider. If null will use the platform default one (Google Maps for Android and MapKit for iOS) | 122 | | **style** | _StyleProp_ | absoluteFillObject | Styling for MapView | 123 | 124 | --- 125 | 126 | ## Children Props 127 | 128 | | Props | Type | Default | Note | 129 | | ------------------------ | ------------ | ----------------------------------------------------- | ---------------------------------------- | 130 | | **isOutsideCluster** | _boolean_ | false | Prevent child from clusterization. **_Required_** for not a Marker children (e.g. Polygon, Polyline, Circle) | 131 | 132 | --- 133 | 134 | > Also contains react-native-maps [\ Props](https://github.com/react-native-community/react-native-maps/blob/master/docs/mapview.md#props) 135 | 136 | ## Events 137 | 138 | | Event Name | Returns | Notes | 139 | | ------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | 140 | | **onClusterClick** | ({ clusterId: number, coordinate : LatLng }, children: Marker[]) | Callback that is called when the user pressed on the **_cluster_** marker | 141 | | **onZoomChange** | void | Callback that is called with updated map zoom in **number** | 142 | 143 | --- 144 | 145 | > Also contains react-native-maps [\ Events](https://github.com/react-native-community/react-native-maps/blob/master/docs/mapview.md#events) 146 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /demo/images/cluster-expand.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/demo/images/cluster-expand.gif -------------------------------------------------------------------------------- /demo/images/custom-marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/demo/images/custom-marker.png -------------------------------------------------------------------------------- /demo/images/nested-cluster-expand.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/demo/images/nested-cluster-expand.gif -------------------------------------------------------------------------------- /demo/images/zoom-in.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/demo/images/zoom-in.gif -------------------------------------------------------------------------------- /demo/images/zoom-out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/demo/images/zoom-out.gif -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { StyleSheet, View, Text, TouchableOpacity } from 'react-native'; 3 | import { PROVIDER_GOOGLE, Marker, Circle } from 'react-native-maps'; 4 | import { ClusterMap } from 'react-native-cluster-map'; 5 | 6 | const markers = [ 7 | { latitude: 37.78825, longitude: -122.4324 }, 8 | { latitude: 37.78925, longitude: -122.4324 }, 9 | { latitude: 37.79, longitude: -122.4324 }, 10 | { latitude: 37.792, longitude: -122.4324 }, 11 | ]; 12 | 13 | const App = () => { 14 | const [markersState, setMarkers] = useState(markers); 15 | 16 | const onAddMarkers = () => { 17 | setMarkers([ 18 | ...markersState, 19 | { latitude: 37.78825, longitude: -122.4247 }, 20 | { latitude: 37.79925, longitude: -122.4247 }, 21 | ]); 22 | }; 23 | 24 | return ( 25 | 26 | 38 | 45 | 52 | 59 | {markersState.map((marker, id) => { 60 | return ; 61 | })} 62 | 63 | 64 | 65 | Add markers 66 | 67 | 68 | ); 69 | }; 70 | 71 | export default App; 72 | 73 | const styles = StyleSheet.create({ 74 | addMarkerButton: { 75 | display: 'flex', 76 | justifyContent: 'center', 77 | padding: 20, 78 | bottom: 30, 79 | left: 30, 80 | position: 'absolute', 81 | backgroundColor: '#F8E473', 82 | borderRadius: 12, 83 | }, 84 | }); 85 | -------------------------------------------------------------------------------- /example/__tests__/App-test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /example/android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.example", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.example", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /example/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: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format 22 | * bundleCommand: "ram-bundle", 23 | * 24 | * // whether to bundle JS and assets in debug mode 25 | * bundleInDebug: false, 26 | * 27 | * // whether to bundle JS and assets in release mode 28 | * bundleInRelease: true, 29 | * 30 | * // whether to bundle JS and assets in another build variant (if configured). 31 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 32 | * // The configuration property can be in the following formats 33 | * // 'bundleIn${productFlavor}${buildType}' 34 | * // 'bundleIn${buildType}' 35 | * // bundleInFreeDebug: true, 36 | * // bundleInPaidRelease: true, 37 | * // bundleInBeta: true, 38 | * 39 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 40 | * // for example: to disable dev mode in the staging build type (if configured) 41 | * devDisabledInStaging: true, 42 | * // The configuration property can be in the following formats 43 | * // 'devDisabledIn${productFlavor}${buildType}' 44 | * // 'devDisabledIn${buildType}' 45 | * 46 | * // the root of your project, i.e. where "package.json" lives 47 | * root: "../../", 48 | * 49 | * // where to put the JS bundle asset in debug mode 50 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 51 | * 52 | * // where to put the JS bundle asset in release mode 53 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 54 | * 55 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 56 | * // require('./image.png')), in debug mode 57 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 58 | * 59 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 60 | * // require('./image.png')), in release mode 61 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 62 | * 63 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 64 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 65 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 66 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 67 | * // for example, you might want to remove it from here. 68 | * inputExcludes: ["android/**", "ios/**"], 69 | * 70 | * // override which node gets called and with what additional arguments 71 | * nodeExecutableAndArgs: ["node"], 72 | * 73 | * // supply additional arguments to the packager 74 | * extraPackagerArgs: [] 75 | * ] 76 | */ 77 | 78 | project.ext.react = [ 79 | entryFile: "index.js", 80 | enableHermes: false, // clean and rebuild if changing 81 | ] 82 | 83 | apply from: "../../node_modules/react-native/react.gradle" 84 | 85 | /** 86 | * Set this to true to create two separate APKs instead of one: 87 | * - An APK that only works on ARM devices 88 | * - An APK that only works on x86 devices 89 | * The advantage is the size of the APK is reduced by about 4MB. 90 | * Upload all the APKs to the Play Store and people will download 91 | * the correct one based on the CPU architecture of their device. 92 | */ 93 | def enableSeparateBuildPerCPUArchitecture = false 94 | 95 | /** 96 | * Run Proguard to shrink the Java bytecode in release builds. 97 | */ 98 | def enableProguardInReleaseBuilds = false 99 | 100 | /** 101 | * The preferred build flavor of JavaScriptCore. 102 | * 103 | * For example, to use the international variant, you can use: 104 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 105 | * 106 | * The international variant includes ICU i18n library and necessary data 107 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 108 | * give correct results when using with locales other than en-US. Note that 109 | * this variant is about 6MiB larger per architecture than default. 110 | */ 111 | def jscFlavor = 'org.webkit:android-jsc:+' 112 | 113 | /** 114 | * Whether to enable the Hermes VM. 115 | * 116 | * This should be set on project.ext.react and mirrored here. If it is not set 117 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode 118 | * and the benefits of using Hermes will therefore be sharply reduced. 119 | */ 120 | def enableHermes = project.ext.react.get("enableHermes", false); 121 | 122 | android { 123 | compileSdkVersion rootProject.ext.compileSdkVersion 124 | 125 | compileOptions { 126 | sourceCompatibility JavaVersion.VERSION_1_8 127 | targetCompatibility JavaVersion.VERSION_1_8 128 | } 129 | 130 | defaultConfig { 131 | applicationId "com.example" 132 | minSdkVersion rootProject.ext.minSdkVersion 133 | targetSdkVersion rootProject.ext.targetSdkVersion 134 | versionCode 1 135 | versionName "1.0" 136 | } 137 | splits { 138 | abi { 139 | reset() 140 | enable enableSeparateBuildPerCPUArchitecture 141 | universalApk false // If true, also generate a universal APK 142 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" 143 | } 144 | } 145 | signingConfigs { 146 | debug { 147 | storeFile file('debug.keystore') 148 | storePassword 'android' 149 | keyAlias 'androiddebugkey' 150 | keyPassword 'android' 151 | } 152 | } 153 | buildTypes { 154 | debug { 155 | signingConfig signingConfigs.debug 156 | } 157 | release { 158 | // Caution! In production, you need to generate your own keystore file. 159 | // see https://facebook.github.io/react-native/docs/signed-apk-android. 160 | signingConfig signingConfigs.debug 161 | minifyEnabled enableProguardInReleaseBuilds 162 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 163 | } 164 | } 165 | // applicationVariants are e.g. debug, release 166 | applicationVariants.all { variant -> 167 | variant.outputs.each { output -> 168 | // For each separate APK per architecture, set a unique version code as described here: 169 | // https://developer.android.com/studio/build/configure-apk-splits.html 170 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 171 | def abi = output.getFilter(OutputFile.ABI) 172 | if (abi != null) { // null for the universal-debug, universal-release variants 173 | output.versionCodeOverride = 174 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 175 | } 176 | 177 | } 178 | } 179 | 180 | packagingOptions { 181 | pickFirst '**/armeabi-v7a/libc++_shared.so' 182 | pickFirst '**/x86/libc++_shared.so' 183 | pickFirst '**/arm64-v8a/libc++_shared.so' 184 | pickFirst '**/x86_64/libc++_shared.so' 185 | pickFirst '**/x86/libjsc.so' 186 | pickFirst '**/armeabi-v7a/libjsc.so' 187 | } 188 | } 189 | 190 | dependencies { 191 | implementation project(':react-native-maps') 192 | implementation fileTree(dir: "libs", include: ["*.jar"]) 193 | implementation "com.facebook.react:react-native:+" // From node_modules 194 | 195 | if (enableHermes) { 196 | def hermesPath = "../../node_modules/hermesvm/android/"; 197 | debugImplementation files(hermesPath + "hermes-debug.aar") 198 | releaseImplementation files(hermesPath + "hermes-release.aar") 199 | } else { 200 | implementation jscFlavor 201 | } 202 | } 203 | 204 | // Run this once to be able to run the application with BUCK 205 | // puts all compile dependencies into folder libs for BUCK to use 206 | task copyDownloadableDepsToLibs(type: Copy) { 207 | from configurations.compile 208 | into 'libs' 209 | } 210 | 211 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 212 | -------------------------------------------------------------------------------- /example/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "example"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.PackageList; 7 | import com.facebook.hermes.reactexecutor.HermesExecutorFactory; 8 | import com.facebook.react.bridge.JavaScriptExecutorFactory; 9 | import com.facebook.react.ReactApplication; 10 | import com.airbnb.android.react.maps.MapsPackage; 11 | import com.facebook.react.ReactNativeHost; 12 | import com.facebook.react.ReactPackage; 13 | import com.facebook.soloader.SoLoader; 14 | 15 | import java.util.List; 16 | 17 | public class MainApplication extends Application implements ReactApplication { 18 | 19 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 20 | @Override 21 | public boolean getUseDeveloperSupport() { 22 | return BuildConfig.DEBUG; 23 | } 24 | 25 | @Override 26 | protected List getPackages() { 27 | @SuppressWarnings("UnnecessaryLocalVariable") 28 | List packages = new PackageList(this).getPackages(); 29 | // Packages that cannot be autolinked yet can be added manually here, for example: 30 | // packages.add(new MyReactNativePackage()); 31 | return packages; 32 | } 33 | 34 | @Override 35 | protected String getJSMainModuleName() { 36 | return "index"; 37 | } 38 | }; 39 | 40 | @Override 41 | public ReactNativeHost getReactNativeHost() { 42 | return mReactNativeHost; 43 | } 44 | 45 | @Override 46 | public void onCreate() { 47 | super.onCreate(); 48 | SoLoader.init(this, /* native exopackage */ false); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Hello App Display Name 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "28.0.3" 6 | minSdkVersion = 16 7 | compileSdkVersion = 28 8 | targetSdkVersion = 28 9 | supportLibVersion = "28.0.0" 10 | } 11 | repositories { 12 | google() 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath("com.android.tools.build:gradle:3.4.1") 17 | 18 | // NOTE: Do not place your application dependencies here; they belong 19 | // in the individual module build.gradle files 20 | } 21 | } 22 | 23 | allprojects { 24 | repositories { 25 | mavenLocal() 26 | maven { 27 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 28 | url("$rootDir/../node_modules/react-native/android") 29 | } 30 | maven { 31 | // Android JSC is installed from npm 32 | url("$rootDir/../node_modules/jsc-android/dist") 33 | } 34 | 35 | google() 36 | jcenter() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/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.useAndroidX=true 21 | android.enableJetifier=true 22 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codempireio/react-native-cluster-map/a9e85a2febcc500a2dbf86ec29573ee5062859ad/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'example' 2 | include ':react-native-maps' 3 | project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/lib/android') 4 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 5 | include ':app' 6 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "displayName": "example" 4 | } -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | target 'example' do 5 | # Pods for example 6 | pod 'React', :path => '../node_modules/react-native/' 7 | pod 'React-Core', :path => '../node_modules/react-native/React' 8 | pod 'React-DevSupport', :path => '../node_modules/react-native/React' 9 | pod 'React-fishhook', :path => '../node_modules/react-native/Libraries/fishhook' 10 | pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' 11 | pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' 12 | pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' 13 | pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' 14 | pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' 15 | pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' 16 | pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' 17 | pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' 18 | pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' 19 | pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket' 20 | 21 | pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' 22 | pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' 23 | pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' 24 | pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' 25 | pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' 26 | 27 | pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' 28 | pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' 29 | pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' 30 | 31 | # React Native Maps dependencies 32 | rn_maps_path = '../node_modules/react-native-maps' 33 | pod 'react-native-google-maps', :path => rn_maps_path 34 | pod 'GoogleMaps' 35 | pod 'Google-Maps-iOS-Utils' 36 | 37 | target 'exampleTests' do 38 | inherit! :search_paths 39 | # Pods for testing 40 | end 41 | 42 | use_native_modules! 43 | end 44 | 45 | target 'example-tvOS' do 46 | # Pods for example-tvOS 47 | 48 | target 'example-tvOSTests' do 49 | inherit! :search_paths 50 | # Pods for testing 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /example/ios/example-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /example/ios/example-tvOSTests/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 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; }; 11 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 12 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 14 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 15 | 1AA3CEA641B7757A23863089 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 48DEAA715472EAB41F676C3D /* libPods-example.a */; }; 16 | 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 17 | 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 18 | 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 19 | 2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; }; 20 | 8F5B6BFB2235575EB562EF0D /* libPods-example-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 398B310FE1A7D86405624A4C /* libPods-example-tvOSTests.a */; }; 21 | 976BC1DEA95DE151351BF617 /* libPods-example-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 86955E9A30D5A5E3D08C6D2A /* libPods-example-tvOS.a */; }; 22 | 9DFCFCF5331CBDFD422C1F26 /* libPods-exampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 99FB6359EC513E3FAA7E8BF5 /* libPods-exampleTests.a */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 13B07F861A680F5B00A75B9A; 31 | remoteInfo = example; 32 | }; 33 | 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7; 38 | remoteInfo = "example-tvOS"; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; 44 | 00E356EE1AD99517003FC87E /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; sourceTree = ""; }; 47 | 13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = ""; }; 49 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/AppDelegate.m; sourceTree = ""; }; 50 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 51 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = ""; }; 52 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; }; 53 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = ""; }; 54 | 2A7A9C0E9E34610B0F1360AD /* Pods-exampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-exampleTests.release.xcconfig"; path = "Target Support Files/Pods-exampleTests/Pods-exampleTests.release.xcconfig"; sourceTree = ""; }; 55 | 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 398B310FE1A7D86405624A4C /* libPods-example-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 48DEAA715472EAB41F676C3D /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 6B62CD7F1CBECDD601E9D7F7 /* Pods-example-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.debug.xcconfig"; sourceTree = ""; }; 60 | 7330C045E43C9497E662026A /* Pods-exampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-exampleTests.debug.xcconfig"; path = "Target Support Files/Pods-exampleTests/Pods-exampleTests.debug.xcconfig"; sourceTree = ""; }; 61 | 86955E9A30D5A5E3D08C6D2A /* libPods-example-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 93D6CEDF40EEE9660CABB43F /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = ""; }; 63 | 99FB6359EC513E3FAA7E8BF5 /* libPods-exampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-exampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | A3FBD2D27FCD16BFD7913F0C /* Pods-example-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.release.xcconfig"; sourceTree = ""; }; 65 | B393EC06BE9173B67F79E72E /* Pods-example-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.release.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.release.xcconfig"; sourceTree = ""; }; 66 | C95D94EF7CB4EDB496E9475C /* Pods-example-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.debug.xcconfig"; sourceTree = ""; }; 67 | D724D4DCCC348AB950D32254 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = ""; }; 68 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 69 | ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 00E356EB1AD99517003FC87E /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | 9DFCFCF5331CBDFD422C1F26 /* libPods-exampleTests.a in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | 1AA3CEA641B7757A23863089 /* libPods-example.a in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 2D02E4781E0B4A5D006451C7 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | 976BC1DEA95DE151351BF617 /* libPods-example-tvOS.a in Frameworks */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 8F5B6BFB2235575EB562EF0D /* libPods-example-tvOSTests.a in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | /* End PBXFrameworksBuildPhase section */ 106 | 107 | /* Begin PBXGroup section */ 108 | 00E356EF1AD99517003FC87E /* exampleTests */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 00E356F21AD99517003FC87E /* exampleTests.m */, 112 | 00E356F01AD99517003FC87E /* Supporting Files */, 113 | ); 114 | path = exampleTests; 115 | sourceTree = ""; 116 | }; 117 | 00E356F01AD99517003FC87E /* Supporting Files */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 00E356F11AD99517003FC87E /* Info.plist */, 121 | ); 122 | name = "Supporting Files"; 123 | sourceTree = ""; 124 | }; 125 | 07C2731B70E563D70AD16526 /* Pods */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 93D6CEDF40EEE9660CABB43F /* Pods-example.debug.xcconfig */, 129 | D724D4DCCC348AB950D32254 /* Pods-example.release.xcconfig */, 130 | 6B62CD7F1CBECDD601E9D7F7 /* Pods-example-tvOS.debug.xcconfig */, 131 | B393EC06BE9173B67F79E72E /* Pods-example-tvOS.release.xcconfig */, 132 | C95D94EF7CB4EDB496E9475C /* Pods-example-tvOSTests.debug.xcconfig */, 133 | A3FBD2D27FCD16BFD7913F0C /* Pods-example-tvOSTests.release.xcconfig */, 134 | 7330C045E43C9497E662026A /* Pods-exampleTests.debug.xcconfig */, 135 | 2A7A9C0E9E34610B0F1360AD /* Pods-exampleTests.release.xcconfig */, 136 | ); 137 | name = Pods; 138 | path = Pods; 139 | sourceTree = ""; 140 | }; 141 | 13B07FAE1A68108700A75B9A /* example */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 145 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 146 | 13B07FB01A68108700A75B9A /* AppDelegate.m */, 147 | 13B07FB51A68108700A75B9A /* Images.xcassets */, 148 | 13B07FB61A68108700A75B9A /* Info.plist */, 149 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 150 | 13B07FB71A68108700A75B9A /* main.m */, 151 | ); 152 | name = example; 153 | sourceTree = ""; 154 | }; 155 | 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */, 159 | ED2971642150620600B7C4FE /* JavaScriptCore.framework */, 160 | 48DEAA715472EAB41F676C3D /* libPods-example.a */, 161 | 86955E9A30D5A5E3D08C6D2A /* libPods-example-tvOS.a */, 162 | 398B310FE1A7D86405624A4C /* libPods-example-tvOSTests.a */, 163 | 99FB6359EC513E3FAA7E8BF5 /* libPods-exampleTests.a */, 164 | ); 165 | name = Frameworks; 166 | sourceTree = ""; 167 | }; 168 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | ); 172 | name = Libraries; 173 | sourceTree = ""; 174 | }; 175 | 83CBB9F61A601CBA00E9B192 = { 176 | isa = PBXGroup; 177 | children = ( 178 | 13B07FAE1A68108700A75B9A /* example */, 179 | 832341AE1AAA6A7D00B99B32 /* Libraries */, 180 | 00E356EF1AD99517003FC87E /* exampleTests */, 181 | 83CBBA001A601CBA00E9B192 /* Products */, 182 | 2D16E6871FA4F8E400B85C8A /* Frameworks */, 183 | 07C2731B70E563D70AD16526 /* Pods */, 184 | ); 185 | indentWidth = 2; 186 | sourceTree = ""; 187 | tabWidth = 2; 188 | usesTabs = 0; 189 | }; 190 | 83CBBA001A601CBA00E9B192 /* Products */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 13B07F961A680F5B00A75B9A /* example.app */, 194 | 00E356EE1AD99517003FC87E /* exampleTests.xctest */, 195 | 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */, 196 | 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */, 197 | ); 198 | name = Products; 199 | sourceTree = ""; 200 | }; 201 | /* End PBXGroup section */ 202 | 203 | /* Begin PBXNativeTarget section */ 204 | 00E356ED1AD99517003FC87E /* exampleTests */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */; 207 | buildPhases = ( 208 | F20F0C714BC31CC4B0D93854 /* [CP] Check Pods Manifest.lock */, 209 | 00E356EA1AD99517003FC87E /* Sources */, 210 | 00E356EB1AD99517003FC87E /* Frameworks */, 211 | 00E356EC1AD99517003FC87E /* Resources */, 212 | ); 213 | buildRules = ( 214 | ); 215 | dependencies = ( 216 | 00E356F51AD99517003FC87E /* PBXTargetDependency */, 217 | ); 218 | name = exampleTests; 219 | productName = exampleTests; 220 | productReference = 00E356EE1AD99517003FC87E /* exampleTests.xctest */; 221 | productType = "com.apple.product-type.bundle.unit-test"; 222 | }; 223 | 13B07F861A680F5B00A75B9A /* example */ = { 224 | isa = PBXNativeTarget; 225 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; 226 | buildPhases = ( 227 | 6CDE96C0802726D975C629C3 /* [CP] Check Pods Manifest.lock */, 228 | FD10A7F022414F080027D42C /* Start Packager */, 229 | 13B07F871A680F5B00A75B9A /* Sources */, 230 | 13B07F8C1A680F5B00A75B9A /* Frameworks */, 231 | 13B07F8E1A680F5B00A75B9A /* Resources */, 232 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 233 | 441F13DACAEFCC518D3C4BC8 /* [CP] Copy Pods Resources */, 234 | ); 235 | buildRules = ( 236 | ); 237 | dependencies = ( 238 | ); 239 | name = example; 240 | productName = example; 241 | productReference = 13B07F961A680F5B00A75B9A /* example.app */; 242 | productType = "com.apple.product-type.application"; 243 | }; 244 | 2D02E47A1E0B4A5D006451C7 /* example-tvOS */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */; 247 | buildPhases = ( 248 | A8FF7C4844B8FE1CEF9DBD7E /* [CP] Check Pods Manifest.lock */, 249 | FD10A7F122414F3F0027D42C /* Start Packager */, 250 | 2D02E4771E0B4A5D006451C7 /* Sources */, 251 | 2D02E4781E0B4A5D006451C7 /* Frameworks */, 252 | 2D02E4791E0B4A5D006451C7 /* Resources */, 253 | 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */, 254 | ); 255 | buildRules = ( 256 | ); 257 | dependencies = ( 258 | ); 259 | name = "example-tvOS"; 260 | productName = "example-tvOS"; 261 | productReference = 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */; 262 | productType = "com.apple.product-type.application"; 263 | }; 264 | 2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */ = { 265 | isa = PBXNativeTarget; 266 | buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */; 267 | buildPhases = ( 268 | 0A642F0A9AF99BE5721E66AB /* [CP] Check Pods Manifest.lock */, 269 | 2D02E48C1E0B4A5D006451C7 /* Sources */, 270 | 2D02E48D1E0B4A5D006451C7 /* Frameworks */, 271 | 2D02E48E1E0B4A5D006451C7 /* Resources */, 272 | ); 273 | buildRules = ( 274 | ); 275 | dependencies = ( 276 | 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */, 277 | ); 278 | name = "example-tvOSTests"; 279 | productName = "example-tvOSTests"; 280 | productReference = 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */; 281 | productType = "com.apple.product-type.bundle.unit-test"; 282 | }; 283 | /* End PBXNativeTarget section */ 284 | 285 | /* Begin PBXProject section */ 286 | 83CBB9F71A601CBA00E9B192 /* Project object */ = { 287 | isa = PBXProject; 288 | attributes = { 289 | LastUpgradeCheck = 0940; 290 | ORGANIZATIONNAME = Facebook; 291 | TargetAttributes = { 292 | 00E356ED1AD99517003FC87E = { 293 | CreatedOnToolsVersion = 6.2; 294 | TestTargetID = 13B07F861A680F5B00A75B9A; 295 | }; 296 | 2D02E47A1E0B4A5D006451C7 = { 297 | CreatedOnToolsVersion = 8.2.1; 298 | ProvisioningStyle = Automatic; 299 | }; 300 | 2D02E48F1E0B4A5D006451C7 = { 301 | CreatedOnToolsVersion = 8.2.1; 302 | ProvisioningStyle = Automatic; 303 | TestTargetID = 2D02E47A1E0B4A5D006451C7; 304 | }; 305 | }; 306 | }; 307 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */; 308 | compatibilityVersion = "Xcode 3.2"; 309 | developmentRegion = English; 310 | hasScannedForEncodings = 0; 311 | knownRegions = ( 312 | en, 313 | Base, 314 | ); 315 | mainGroup = 83CBB9F61A601CBA00E9B192; 316 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; 317 | projectDirPath = ""; 318 | projectRoot = ""; 319 | targets = ( 320 | 13B07F861A680F5B00A75B9A /* example */, 321 | 00E356ED1AD99517003FC87E /* exampleTests */, 322 | 2D02E47A1E0B4A5D006451C7 /* example-tvOS */, 323 | 2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */, 324 | ); 325 | }; 326 | /* End PBXProject section */ 327 | 328 | /* Begin PBXResourcesBuildPhase section */ 329 | 00E356EC1AD99517003FC87E /* Resources */ = { 330 | isa = PBXResourcesBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | 13B07F8E1A680F5B00A75B9A /* Resources */ = { 337 | isa = PBXResourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 341 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | 2D02E4791E0B4A5D006451C7 /* Resources */ = { 346 | isa = PBXResourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */, 350 | ); 351 | runOnlyForDeploymentPostprocessing = 0; 352 | }; 353 | 2D02E48E1E0B4A5D006451C7 /* Resources */ = { 354 | isa = PBXResourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | /* End PBXResourcesBuildPhase section */ 361 | 362 | /* Begin PBXShellScriptBuildPhase section */ 363 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { 364 | isa = PBXShellScriptBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | ); 368 | inputPaths = ( 369 | ); 370 | name = "Bundle React Native code and images"; 371 | outputPaths = ( 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | shellPath = /bin/sh; 375 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; 376 | }; 377 | 0A642F0A9AF99BE5721E66AB /* [CP] Check Pods Manifest.lock */ = { 378 | isa = PBXShellScriptBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | ); 382 | inputFileListPaths = ( 383 | ); 384 | inputPaths = ( 385 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 386 | "${PODS_ROOT}/Manifest.lock", 387 | ); 388 | name = "[CP] Check Pods Manifest.lock"; 389 | outputFileListPaths = ( 390 | ); 391 | outputPaths = ( 392 | "$(DERIVED_FILE_DIR)/Pods-example-tvOSTests-checkManifestLockResult.txt", 393 | ); 394 | runOnlyForDeploymentPostprocessing = 0; 395 | shellPath = /bin/sh; 396 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 397 | showEnvVarsInLog = 0; 398 | }; 399 | 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = { 400 | isa = PBXShellScriptBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | ); 404 | inputPaths = ( 405 | ); 406 | name = "Bundle React Native Code And Images"; 407 | outputPaths = ( 408 | ); 409 | runOnlyForDeploymentPostprocessing = 0; 410 | shellPath = /bin/sh; 411 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; 412 | }; 413 | 441F13DACAEFCC518D3C4BC8 /* [CP] Copy Pods Resources */ = { 414 | isa = PBXShellScriptBuildPhase; 415 | buildActionMask = 2147483647; 416 | files = ( 417 | ); 418 | inputPaths = ( 419 | "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh", 420 | "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", 421 | ); 422 | name = "[CP] Copy Pods Resources"; 423 | outputPaths = ( 424 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", 425 | ); 426 | runOnlyForDeploymentPostprocessing = 0; 427 | shellPath = /bin/sh; 428 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n"; 429 | showEnvVarsInLog = 0; 430 | }; 431 | 6CDE96C0802726D975C629C3 /* [CP] Check Pods Manifest.lock */ = { 432 | isa = PBXShellScriptBuildPhase; 433 | buildActionMask = 2147483647; 434 | files = ( 435 | ); 436 | inputFileListPaths = ( 437 | ); 438 | inputPaths = ( 439 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 440 | "${PODS_ROOT}/Manifest.lock", 441 | ); 442 | name = "[CP] Check Pods Manifest.lock"; 443 | outputFileListPaths = ( 444 | ); 445 | outputPaths = ( 446 | "$(DERIVED_FILE_DIR)/Pods-example-checkManifestLockResult.txt", 447 | ); 448 | runOnlyForDeploymentPostprocessing = 0; 449 | shellPath = /bin/sh; 450 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 451 | showEnvVarsInLog = 0; 452 | }; 453 | A8FF7C4844B8FE1CEF9DBD7E /* [CP] Check Pods Manifest.lock */ = { 454 | isa = PBXShellScriptBuildPhase; 455 | buildActionMask = 2147483647; 456 | files = ( 457 | ); 458 | inputFileListPaths = ( 459 | ); 460 | inputPaths = ( 461 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 462 | "${PODS_ROOT}/Manifest.lock", 463 | ); 464 | name = "[CP] Check Pods Manifest.lock"; 465 | outputFileListPaths = ( 466 | ); 467 | outputPaths = ( 468 | "$(DERIVED_FILE_DIR)/Pods-example-tvOS-checkManifestLockResult.txt", 469 | ); 470 | runOnlyForDeploymentPostprocessing = 0; 471 | shellPath = /bin/sh; 472 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 473 | showEnvVarsInLog = 0; 474 | }; 475 | F20F0C714BC31CC4B0D93854 /* [CP] Check Pods Manifest.lock */ = { 476 | isa = PBXShellScriptBuildPhase; 477 | buildActionMask = 2147483647; 478 | files = ( 479 | ); 480 | inputFileListPaths = ( 481 | ); 482 | inputPaths = ( 483 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 484 | "${PODS_ROOT}/Manifest.lock", 485 | ); 486 | name = "[CP] Check Pods Manifest.lock"; 487 | outputFileListPaths = ( 488 | ); 489 | outputPaths = ( 490 | "$(DERIVED_FILE_DIR)/Pods-exampleTests-checkManifestLockResult.txt", 491 | ); 492 | runOnlyForDeploymentPostprocessing = 0; 493 | shellPath = /bin/sh; 494 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 495 | showEnvVarsInLog = 0; 496 | }; 497 | FD10A7F022414F080027D42C /* Start Packager */ = { 498 | isa = PBXShellScriptBuildPhase; 499 | buildActionMask = 2147483647; 500 | files = ( 501 | ); 502 | inputFileListPaths = ( 503 | ); 504 | inputPaths = ( 505 | ); 506 | name = "Start Packager"; 507 | outputFileListPaths = ( 508 | ); 509 | outputPaths = ( 510 | ); 511 | runOnlyForDeploymentPostprocessing = 0; 512 | shellPath = /bin/sh; 513 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; 514 | showEnvVarsInLog = 0; 515 | }; 516 | FD10A7F122414F3F0027D42C /* Start Packager */ = { 517 | isa = PBXShellScriptBuildPhase; 518 | buildActionMask = 2147483647; 519 | files = ( 520 | ); 521 | inputFileListPaths = ( 522 | ); 523 | inputPaths = ( 524 | ); 525 | name = "Start Packager"; 526 | outputFileListPaths = ( 527 | ); 528 | outputPaths = ( 529 | ); 530 | runOnlyForDeploymentPostprocessing = 0; 531 | shellPath = /bin/sh; 532 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; 533 | showEnvVarsInLog = 0; 534 | }; 535 | /* End PBXShellScriptBuildPhase section */ 536 | 537 | /* Begin PBXSourcesBuildPhase section */ 538 | 00E356EA1AD99517003FC87E /* Sources */ = { 539 | isa = PBXSourcesBuildPhase; 540 | buildActionMask = 2147483647; 541 | files = ( 542 | 00E356F31AD99517003FC87E /* exampleTests.m in Sources */, 543 | ); 544 | runOnlyForDeploymentPostprocessing = 0; 545 | }; 546 | 13B07F871A680F5B00A75B9A /* Sources */ = { 547 | isa = PBXSourcesBuildPhase; 548 | buildActionMask = 2147483647; 549 | files = ( 550 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 551 | 13B07FC11A68108700A75B9A /* main.m in Sources */, 552 | ); 553 | runOnlyForDeploymentPostprocessing = 0; 554 | }; 555 | 2D02E4771E0B4A5D006451C7 /* Sources */ = { 556 | isa = PBXSourcesBuildPhase; 557 | buildActionMask = 2147483647; 558 | files = ( 559 | 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */, 560 | 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */, 561 | ); 562 | runOnlyForDeploymentPostprocessing = 0; 563 | }; 564 | 2D02E48C1E0B4A5D006451C7 /* Sources */ = { 565 | isa = PBXSourcesBuildPhase; 566 | buildActionMask = 2147483647; 567 | files = ( 568 | 2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */, 569 | ); 570 | runOnlyForDeploymentPostprocessing = 0; 571 | }; 572 | /* End PBXSourcesBuildPhase section */ 573 | 574 | /* Begin PBXTargetDependency section */ 575 | 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { 576 | isa = PBXTargetDependency; 577 | target = 13B07F861A680F5B00A75B9A /* example */; 578 | targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; 579 | }; 580 | 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = { 581 | isa = PBXTargetDependency; 582 | target = 2D02E47A1E0B4A5D006451C7 /* example-tvOS */; 583 | targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */; 584 | }; 585 | /* End PBXTargetDependency section */ 586 | 587 | /* Begin PBXVariantGroup section */ 588 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { 589 | isa = PBXVariantGroup; 590 | children = ( 591 | 13B07FB21A68108700A75B9A /* Base */, 592 | ); 593 | name = LaunchScreen.xib; 594 | path = example; 595 | sourceTree = ""; 596 | }; 597 | /* End PBXVariantGroup section */ 598 | 599 | /* Begin XCBuildConfiguration section */ 600 | 00E356F61AD99517003FC87E /* Debug */ = { 601 | isa = XCBuildConfiguration; 602 | baseConfigurationReference = 7330C045E43C9497E662026A /* Pods-exampleTests.debug.xcconfig */; 603 | buildSettings = { 604 | BUNDLE_LOADER = "$(TEST_HOST)"; 605 | GCC_PREPROCESSOR_DEFINITIONS = ( 606 | "DEBUG=1", 607 | "$(inherited)", 608 | ); 609 | INFOPLIST_FILE = exampleTests/Info.plist; 610 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 611 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 612 | OTHER_LDFLAGS = ( 613 | "-ObjC", 614 | "-lc++", 615 | "$(inherited)", 616 | ); 617 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 618 | PRODUCT_NAME = "$(TARGET_NAME)"; 619 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example"; 620 | }; 621 | name = Debug; 622 | }; 623 | 00E356F71AD99517003FC87E /* Release */ = { 624 | isa = XCBuildConfiguration; 625 | baseConfigurationReference = 2A7A9C0E9E34610B0F1360AD /* Pods-exampleTests.release.xcconfig */; 626 | buildSettings = { 627 | BUNDLE_LOADER = "$(TEST_HOST)"; 628 | COPY_PHASE_STRIP = NO; 629 | INFOPLIST_FILE = exampleTests/Info.plist; 630 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 631 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 632 | OTHER_LDFLAGS = ( 633 | "-ObjC", 634 | "-lc++", 635 | "$(inherited)", 636 | ); 637 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 638 | PRODUCT_NAME = "$(TARGET_NAME)"; 639 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example"; 640 | }; 641 | name = Release; 642 | }; 643 | 13B07F941A680F5B00A75B9A /* Debug */ = { 644 | isa = XCBuildConfiguration; 645 | baseConfigurationReference = 93D6CEDF40EEE9660CABB43F /* Pods-example.debug.xcconfig */; 646 | buildSettings = { 647 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 648 | CURRENT_PROJECT_VERSION = 1; 649 | DEAD_CODE_STRIPPING = NO; 650 | INFOPLIST_FILE = example/Info.plist; 651 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 652 | OTHER_LDFLAGS = ( 653 | "$(inherited)", 654 | "-ObjC", 655 | "-lc++", 656 | ); 657 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 658 | PRODUCT_NAME = example; 659 | VERSIONING_SYSTEM = "apple-generic"; 660 | }; 661 | name = Debug; 662 | }; 663 | 13B07F951A680F5B00A75B9A /* Release */ = { 664 | isa = XCBuildConfiguration; 665 | baseConfigurationReference = D724D4DCCC348AB950D32254 /* Pods-example.release.xcconfig */; 666 | buildSettings = { 667 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 668 | CURRENT_PROJECT_VERSION = 1; 669 | INFOPLIST_FILE = example/Info.plist; 670 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 671 | OTHER_LDFLAGS = ( 672 | "$(inherited)", 673 | "-ObjC", 674 | "-lc++", 675 | ); 676 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 677 | PRODUCT_NAME = example; 678 | VERSIONING_SYSTEM = "apple-generic"; 679 | }; 680 | name = Release; 681 | }; 682 | 2D02E4971E0B4A5E006451C7 /* Debug */ = { 683 | isa = XCBuildConfiguration; 684 | baseConfigurationReference = 6B62CD7F1CBECDD601E9D7F7 /* Pods-example-tvOS.debug.xcconfig */; 685 | buildSettings = { 686 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 687 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 688 | CLANG_ANALYZER_NONNULL = YES; 689 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 690 | CLANG_WARN_INFINITE_RECURSION = YES; 691 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 692 | DEBUG_INFORMATION_FORMAT = dwarf; 693 | ENABLE_TESTABILITY = YES; 694 | GCC_NO_COMMON_BLOCKS = YES; 695 | INFOPLIST_FILE = "example-tvOS/Info.plist"; 696 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 697 | OTHER_LDFLAGS = ( 698 | "$(inherited)", 699 | "-ObjC", 700 | "-lc++", 701 | ); 702 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS"; 703 | PRODUCT_NAME = "$(TARGET_NAME)"; 704 | SDKROOT = appletvos; 705 | TARGETED_DEVICE_FAMILY = 3; 706 | TVOS_DEPLOYMENT_TARGET = 9.2; 707 | }; 708 | name = Debug; 709 | }; 710 | 2D02E4981E0B4A5E006451C7 /* Release */ = { 711 | isa = XCBuildConfiguration; 712 | baseConfigurationReference = B393EC06BE9173B67F79E72E /* Pods-example-tvOS.release.xcconfig */; 713 | buildSettings = { 714 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 715 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 716 | CLANG_ANALYZER_NONNULL = YES; 717 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 718 | CLANG_WARN_INFINITE_RECURSION = YES; 719 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 720 | COPY_PHASE_STRIP = NO; 721 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 722 | GCC_NO_COMMON_BLOCKS = YES; 723 | INFOPLIST_FILE = "example-tvOS/Info.plist"; 724 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 725 | OTHER_LDFLAGS = ( 726 | "$(inherited)", 727 | "-ObjC", 728 | "-lc++", 729 | ); 730 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS"; 731 | PRODUCT_NAME = "$(TARGET_NAME)"; 732 | SDKROOT = appletvos; 733 | TARGETED_DEVICE_FAMILY = 3; 734 | TVOS_DEPLOYMENT_TARGET = 9.2; 735 | }; 736 | name = Release; 737 | }; 738 | 2D02E4991E0B4A5E006451C7 /* Debug */ = { 739 | isa = XCBuildConfiguration; 740 | baseConfigurationReference = C95D94EF7CB4EDB496E9475C /* Pods-example-tvOSTests.debug.xcconfig */; 741 | buildSettings = { 742 | BUNDLE_LOADER = "$(TEST_HOST)"; 743 | CLANG_ANALYZER_NONNULL = YES; 744 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 745 | CLANG_WARN_INFINITE_RECURSION = YES; 746 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 747 | DEBUG_INFORMATION_FORMAT = dwarf; 748 | ENABLE_TESTABILITY = YES; 749 | GCC_NO_COMMON_BLOCKS = YES; 750 | INFOPLIST_FILE = "example-tvOSTests/Info.plist"; 751 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 752 | OTHER_LDFLAGS = ( 753 | "$(inherited)", 754 | "-ObjC", 755 | "-lc++", 756 | ); 757 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests"; 758 | PRODUCT_NAME = "$(TARGET_NAME)"; 759 | SDKROOT = appletvos; 760 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS"; 761 | TVOS_DEPLOYMENT_TARGET = 10.1; 762 | }; 763 | name = Debug; 764 | }; 765 | 2D02E49A1E0B4A5E006451C7 /* Release */ = { 766 | isa = XCBuildConfiguration; 767 | baseConfigurationReference = A3FBD2D27FCD16BFD7913F0C /* Pods-example-tvOSTests.release.xcconfig */; 768 | buildSettings = { 769 | BUNDLE_LOADER = "$(TEST_HOST)"; 770 | CLANG_ANALYZER_NONNULL = YES; 771 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 772 | CLANG_WARN_INFINITE_RECURSION = YES; 773 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 774 | COPY_PHASE_STRIP = NO; 775 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 776 | GCC_NO_COMMON_BLOCKS = YES; 777 | INFOPLIST_FILE = "example-tvOSTests/Info.plist"; 778 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 779 | OTHER_LDFLAGS = ( 780 | "$(inherited)", 781 | "-ObjC", 782 | "-lc++", 783 | ); 784 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests"; 785 | PRODUCT_NAME = "$(TARGET_NAME)"; 786 | SDKROOT = appletvos; 787 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS"; 788 | TVOS_DEPLOYMENT_TARGET = 10.1; 789 | }; 790 | name = Release; 791 | }; 792 | 83CBBA201A601CBA00E9B192 /* Debug */ = { 793 | isa = XCBuildConfiguration; 794 | buildSettings = { 795 | ALWAYS_SEARCH_USER_PATHS = NO; 796 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 797 | CLANG_CXX_LIBRARY = "libc++"; 798 | CLANG_ENABLE_MODULES = YES; 799 | CLANG_ENABLE_OBJC_ARC = YES; 800 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 801 | CLANG_WARN_BOOL_CONVERSION = YES; 802 | CLANG_WARN_COMMA = YES; 803 | CLANG_WARN_CONSTANT_CONVERSION = YES; 804 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 805 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 806 | CLANG_WARN_EMPTY_BODY = YES; 807 | CLANG_WARN_ENUM_CONVERSION = YES; 808 | CLANG_WARN_INFINITE_RECURSION = YES; 809 | CLANG_WARN_INT_CONVERSION = YES; 810 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 811 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 812 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 813 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 814 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 815 | CLANG_WARN_STRICT_PROTOTYPES = YES; 816 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 817 | CLANG_WARN_UNREACHABLE_CODE = YES; 818 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 819 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 820 | COPY_PHASE_STRIP = NO; 821 | ENABLE_STRICT_OBJC_MSGSEND = YES; 822 | ENABLE_TESTABILITY = YES; 823 | GCC_C_LANGUAGE_STANDARD = gnu99; 824 | GCC_DYNAMIC_NO_PIC = NO; 825 | GCC_NO_COMMON_BLOCKS = YES; 826 | GCC_OPTIMIZATION_LEVEL = 0; 827 | GCC_PREPROCESSOR_DEFINITIONS = ( 828 | "DEBUG=1", 829 | "$(inherited)", 830 | ); 831 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 832 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 833 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 834 | GCC_WARN_UNDECLARED_SELECTOR = YES; 835 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 836 | GCC_WARN_UNUSED_FUNCTION = YES; 837 | GCC_WARN_UNUSED_VARIABLE = YES; 838 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 839 | MTL_ENABLE_DEBUG_INFO = YES; 840 | ONLY_ACTIVE_ARCH = YES; 841 | SDKROOT = iphoneos; 842 | }; 843 | name = Debug; 844 | }; 845 | 83CBBA211A601CBA00E9B192 /* Release */ = { 846 | isa = XCBuildConfiguration; 847 | buildSettings = { 848 | ALWAYS_SEARCH_USER_PATHS = NO; 849 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 850 | CLANG_CXX_LIBRARY = "libc++"; 851 | CLANG_ENABLE_MODULES = YES; 852 | CLANG_ENABLE_OBJC_ARC = YES; 853 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 854 | CLANG_WARN_BOOL_CONVERSION = YES; 855 | CLANG_WARN_COMMA = YES; 856 | CLANG_WARN_CONSTANT_CONVERSION = YES; 857 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 858 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 859 | CLANG_WARN_EMPTY_BODY = YES; 860 | CLANG_WARN_ENUM_CONVERSION = YES; 861 | CLANG_WARN_INFINITE_RECURSION = YES; 862 | CLANG_WARN_INT_CONVERSION = YES; 863 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 864 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 865 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 866 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 867 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 868 | CLANG_WARN_STRICT_PROTOTYPES = YES; 869 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 870 | CLANG_WARN_UNREACHABLE_CODE = YES; 871 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 872 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 873 | COPY_PHASE_STRIP = YES; 874 | ENABLE_NS_ASSERTIONS = NO; 875 | ENABLE_STRICT_OBJC_MSGSEND = YES; 876 | GCC_C_LANGUAGE_STANDARD = gnu99; 877 | GCC_NO_COMMON_BLOCKS = YES; 878 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 879 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 880 | GCC_WARN_UNDECLARED_SELECTOR = YES; 881 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 882 | GCC_WARN_UNUSED_FUNCTION = YES; 883 | GCC_WARN_UNUSED_VARIABLE = YES; 884 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 885 | MTL_ENABLE_DEBUG_INFO = NO; 886 | SDKROOT = iphoneos; 887 | VALIDATE_PRODUCT = YES; 888 | }; 889 | name = Release; 890 | }; 891 | /* End XCBuildConfiguration section */ 892 | 893 | /* Begin XCConfigurationList section */ 894 | 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */ = { 895 | isa = XCConfigurationList; 896 | buildConfigurations = ( 897 | 00E356F61AD99517003FC87E /* Debug */, 898 | 00E356F71AD99517003FC87E /* Release */, 899 | ); 900 | defaultConfigurationIsVisible = 0; 901 | defaultConfigurationName = Release; 902 | }; 903 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */ = { 904 | isa = XCConfigurationList; 905 | buildConfigurations = ( 906 | 13B07F941A680F5B00A75B9A /* Debug */, 907 | 13B07F951A680F5B00A75B9A /* Release */, 908 | ); 909 | defaultConfigurationIsVisible = 0; 910 | defaultConfigurationName = Release; 911 | }; 912 | 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */ = { 913 | isa = XCConfigurationList; 914 | buildConfigurations = ( 915 | 2D02E4971E0B4A5E006451C7 /* Debug */, 916 | 2D02E4981E0B4A5E006451C7 /* Release */, 917 | ); 918 | defaultConfigurationIsVisible = 0; 919 | defaultConfigurationName = Release; 920 | }; 921 | 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */ = { 922 | isa = XCConfigurationList; 923 | buildConfigurations = ( 924 | 2D02E4991E0B4A5E006451C7 /* Debug */, 925 | 2D02E49A1E0B4A5E006451C7 /* Release */, 926 | ); 927 | defaultConfigurationIsVisible = 0; 928 | defaultConfigurationName = Release; 929 | }; 930 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = { 931 | isa = XCConfigurationList; 932 | buildConfigurations = ( 933 | 83CBBA201A601CBA00E9B192 /* Debug */, 934 | 83CBBA211A601CBA00E9B192 /* Release */, 935 | ); 936 | defaultConfigurationIsVisible = 0; 937 | defaultConfigurationName = Release; 938 | }; 939 | /* End XCConfigurationList section */ 940 | }; 941 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; 942 | } 943 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (nonatomic, strong) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | #import 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | [GMSServices provideAPIKey:@"AIzaSyDxEvhzNHkgOlKkrX9xSIrZhoYWE7UfN5A"]; 20 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 21 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 22 | moduleName:@"example" 23 | initialProperties:nil]; 24 | 25 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 26 | 27 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 28 | UIViewController *rootViewController = [UIViewController new]; 29 | rootViewController.view = rootView; 30 | self.window.rootViewController = rootViewController; 31 | [self.window makeKeyAndVisible]; 32 | return YES; 33 | } 34 | 35 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 36 | { 37 | #if DEBUG 38 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 39 | #else 40 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 41 | #endif 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /example/ios/example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /example/ios/example/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Hello App Display Name 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /example/ios/example/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/ios/exampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/exampleTests/exampleTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 16 | 17 | @interface exampleTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation exampleTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 44 | if (level >= RCTLogLevelError) { 45 | redboxError = message; 46 | } 47 | }); 48 | 49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 52 | 53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 55 | return YES; 56 | } 57 | return NO; 58 | }]; 59 | } 60 | 61 | RCTSetLogFunction(RCTDefaultLogFunction); 62 | 63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: false, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "react-native start", 7 | "test": "jest" 8 | }, 9 | "dependencies": { 10 | "react": "16.8.6", 11 | "react-native": "0.60.3", 12 | "react-native-cluster-map": "^1.0.8", 13 | "react-native-maps": "^0.25.0" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.5.0", 17 | "@babel/runtime": "^7.5.0", 18 | "@react-native-community/eslint-config": "^0.0.3", 19 | "@types/jest": "^24.0.15", 20 | "@types/react": "^16.8.23", 21 | "@types/react-native": "^0.60.1", 22 | "@types/react-test-renderer": "^16.8.2", 23 | "babel-jest": "^24.1.0", 24 | "jest": "^24.1.0", 25 | "metro-react-native-babel-preset": "^0.54.1", 26 | "react-test-renderer": "16.8.6", 27 | "typescript": "^3.5.3" 28 | }, 29 | "jest": { 30 | "preset": "react-native", 31 | "moduleFileExtensions": [ 32 | "ts", 33 | "tsx", 34 | "js", 35 | "jsx", 36 | "json", 37 | "node" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/private/var/folders/jy/p6cc3vwj34j5tytjz8n5btlh0000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | // clearMocks: false, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | // coverageDirectory: null, 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // A path to a custom dependency extractor 46 | // dependencyExtractor: null, 47 | 48 | // Make calling deprecated APIs throw helpful error messages 49 | // errorOnDeprecated: false, 50 | 51 | // Force coverage collection from ignored files usin a array of glob patterns 52 | // forceCoverageMatch: [], 53 | 54 | // A path to a module which exports an async function that is triggered once before all test suites 55 | // globalSetup: null, 56 | 57 | // A path to a module which exports an async function that is triggered once after all test suites 58 | // globalTeardown: null, 59 | 60 | // A set of global variables that need to be available in all test environments 61 | // globals: {}, 62 | 63 | // An array of directory names to be searched recursively up from the requiring module's location 64 | // moduleDirectories: [ 65 | // "node_modules" 66 | // ], 67 | 68 | // An array of file extensions your modules use 69 | moduleFileExtensions: ['json', 'ts', 'tsx', 'node', 'js'], 70 | 71 | // A map from regular expressions to module names that allow to stub out resources with a single module 72 | // moduleNameMapper: {}, 73 | 74 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 75 | modulePathIgnorePatterns: ['example'], 76 | 77 | // Activates notifications for test results 78 | // notify: false, 79 | 80 | // An enum that specifies notification mode. Requires { notify: true } 81 | // notifyMode: "failure-change", 82 | 83 | // A preset that is used as a base for Jest's configuration 84 | preset: 'react-native', 85 | 86 | // Run tests from one or more projects 87 | // projects: null, 88 | 89 | // Use this configuration option to add custom reporters to Jest 90 | // reporters: undefined, 91 | 92 | // Automatically reset mock state between every test 93 | // resetMocks: false, 94 | 95 | // Reset the module registry before running each individual test 96 | // resetModules: false, 97 | 98 | // A path to a custom resolver 99 | // resolver: null, 100 | 101 | // Automatically restore mock state between every test 102 | // restoreMocks: false, 103 | 104 | // The root directory that Jest should scan for tests and modules within 105 | // rootDir: null, 106 | 107 | // A list of paths to directories that Jest should use to search for files in 108 | // roots: [ 109 | // "" 110 | // ], 111 | 112 | // Allows you to use a custom runner instead of Jest's default test runner 113 | // runner: "jest-runner", 114 | 115 | // The paths to modules that run some code to configure or set up the testing environment before each test 116 | // setupFiles: [], 117 | 118 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 119 | // setupFilesAfterEnv: [], 120 | 121 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 122 | // snapshotSerializers: [], 123 | 124 | // The test environment that will be used for testing 125 | // testEnvironment: "jest-environment-jsdom", 126 | 127 | // Options that will be passed to the testEnvironment 128 | // testEnvironmentOptions: {}, 129 | 130 | // Adds a location field to test results 131 | // testLocationInResults: false, 132 | 133 | // The glob patterns Jest uses to detect test files 134 | // testMatch: [ 135 | // "**/__tests__/**/*.[jt]s?(x)", 136 | // "**/?(*.)+(spec|test).[tj]s?(x)" 137 | // ], 138 | 139 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 140 | testPathIgnorePatterns: ['/node_modules/', 'example'], 141 | 142 | // The regexp pattern or array of patterns that Jest uses to detect test files 143 | // testRegex: [], 144 | 145 | // This option allows the use of a custom results processor 146 | // testResultsProcessor: null, 147 | 148 | // This option allows use of a custom test runner 149 | // testRunner: "jasmine2", 150 | 151 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 152 | // testURL: "http://localhost", 153 | 154 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 155 | // timers: "real", 156 | 157 | // A map from regular expressions to paths to transformers 158 | // transform: null, 159 | 160 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 161 | transformIgnorePatterns: ['/example/node_modules'], 162 | 163 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 164 | // unmockedModulePathPatterns: undefined, 165 | 166 | // Indicates whether each individual test should be reported during the run 167 | // verbose: null, 168 | 169 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 170 | // watchPathIgnorePatterns: [], 171 | 172 | // Whether to use watchman for file crawling 173 | // watchman: true, 174 | }; 175 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-cluster-map", 3 | "version": "1.0.9", 4 | "description": "React Native MapView clustering component for iOS + Android", 5 | "keywords": [ 6 | "android", 7 | "cluster", 8 | "clustering", 9 | "geolocation", 10 | "google-maps", 11 | "iOS", 12 | "map", 13 | "map-cluster", 14 | "react", 15 | "react-component", 16 | "react-native", 17 | "supercluster" 18 | ], 19 | "homepage": "https://github.com/codempireio/react-native-cluster-map#readme", 20 | "bugs": { 21 | "url": "https://github.com/codempireio/react-native-cluster-map/issues" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/codempireio/react-native-cluster-map.git" 26 | }, 27 | "license": "MIT", 28 | "author": "codempire.io", 29 | "files": [ 30 | "lib", 31 | "example" 32 | ], 33 | "main": "lib/index.js", 34 | "module": "lib/index.es.js", 35 | "types": "lib/index.d.ts", 36 | "scripts": { 37 | "build": "rollup -c", 38 | "lint": "tslint 'src/**/*.{ts,tsx}'", 39 | "prepublishOnly": "yarn build", 40 | "precommit": "lint-staged && npm test", 41 | "prettier": "prettier --config ./.prettierrc --write \"./src/**/*.{ts,tsx}\"", 42 | "sort": "sort-package-json", 43 | "test": "jest" 44 | }, 45 | "lint-staged": { 46 | "*.{ts,tsx}": [ 47 | "yarn prettier", 48 | "yarn lint", 49 | "git add" 50 | ] 51 | }, 52 | "dependencies": { 53 | "@mapbox/geo-viewport": "0.4.0", 54 | "@types/jest": "^24.0.18", 55 | "geojson": "0.5.0", 56 | "jest": "^24.9.0", 57 | "lodash.isequal": "4.5.0", 58 | "supercluster": "6.0.0" 59 | }, 60 | "devDependencies": { 61 | "@types/lodash.isequal": "4.5.5", 62 | "@types/react": "16.8.10", 63 | "@types/react-native": "0.57.42", 64 | "@types/react-test-renderer": "^16.9.0", 65 | "@types/supercluster": "5.0.1", 66 | "babel-loader": "8.0.5", 67 | "lint-staged": "^9.4.0", 68 | "prettier": "1.16.4", 69 | "react": "^16.9.0", 70 | "react-native": "0.59.2", 71 | "react-native-maps": "0.23.0", 72 | "react-test-renderer": "^16.9.0", 73 | "rollup": "1.8.0", 74 | "rollup-plugin-typescript2": "0.20.1", 75 | "sort-package-json": "1.22.1", 76 | "tslint": "5.15.0", 77 | "tslint-config-prettier": "1.18.0", 78 | "tslint-config-standard": "8.0.1", 79 | "tslint-react": "4.0.0", 80 | "typescript": "3.4.1" 81 | }, 82 | "peerDependencies": { 83 | "react": ">=16.0.0", 84 | "react-native": ">=0.50.0", 85 | "react-native-maps": ">=0.23.0" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | 3 | import pkg from './package.json'; 4 | 5 | const tsconfigOverride = { compilerOptions: { module: 'es2015' } }; 6 | 7 | export default { 8 | input: 'src/index.ts', 9 | output: [ 10 | { 11 | file: pkg.main, 12 | format: 'cjs', 13 | }, 14 | { 15 | file: pkg.module, 16 | format: 'es', 17 | }, 18 | ], 19 | external: [ 20 | ...Object.keys(pkg.dependencies || {}), 21 | ...Object.keys(pkg.peerDependencies || {}), 22 | ], 23 | plugins: [ 24 | typescript({ 25 | typescript: require('typescript'), 26 | tsconfigOverride, 27 | }), 28 | ], 29 | }; 30 | -------------------------------------------------------------------------------- /src/cluster-map.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet } from 'react-native'; 3 | import MapView, { 4 | Region, 5 | PROVIDER_GOOGLE, 6 | PROVIDER_DEFAULT, 7 | } from 'react-native-maps'; 8 | import isEqual from 'lodash.isequal'; 9 | 10 | import { ClusterMarker } from './cluster-marker'; 11 | import { clusterService } from './cluster-service'; 12 | import * as utils from './utils'; 13 | 14 | import { 15 | IClusterMapProps, 16 | IClusterMapState, 17 | IClusterClickEvent, 18 | } from './typings'; 19 | 20 | const CLUSTER_EXPAND_TIME = 100; 21 | 22 | export class ClusterMap extends React.PureComponent< 23 | IClusterMapProps, 24 | IClusterMapState 25 | > { 26 | public static defaultProps: Partial = { 27 | isClusterExpandClick: true, 28 | }; 29 | public mapRef: MapView; 30 | public state: IClusterMapState = { 31 | markers: [], 32 | isMapLoaded: false, 33 | currentZoom: null, 34 | }; 35 | 36 | public render() { 37 | const { style, region, priorityMarker, provider } = this.props; 38 | 39 | return ( 40 | (this.mapRef = ref)} 43 | style={style || styles.map} 44 | onMapReady={this.onMapReady} 45 | initialRegion={region} 46 | onRegionChangeComplete={this.onRegionChangeComplete} 47 | provider={provider === PROVIDER_DEFAULT ? null : PROVIDER_GOOGLE} 48 | > 49 | {this.state.isMapLoaded && this.renderContent()} 50 | {priorityMarker ? priorityMarker : null} 51 | 52 | ); 53 | } 54 | 55 | public componentDidMount() { 56 | this.clusterize(); 57 | } 58 | 59 | public componentDidUpdate( 60 | prevProps: IClusterMapProps, 61 | prevState: IClusterMapState 62 | ) { 63 | if ( 64 | isEqual(this.props.children, prevProps.children) && 65 | isEqual(this.state.currentZoom, prevState.currentZoom) 66 | ) { 67 | return; 68 | } 69 | this.clusterize(); 70 | } 71 | 72 | private generateMarkers(region: Region) { 73 | const { markers, zoom } = clusterService.getClustersOptions( 74 | region, 75 | this.state.currentZoom 76 | ); 77 | if (this.props.onZoomChange) { 78 | this.props.onZoomChange(zoom); 79 | } 80 | 81 | this.setState({ 82 | markers, 83 | }); 84 | } 85 | 86 | private onRegionChangeComplete = (region: Region) => { 87 | const zoom = clusterService.getCurrentZoom(region); 88 | if (this.state.currentZoom !== zoom) { 89 | this.setState({ 90 | currentZoom: zoom, 91 | }); 92 | } 93 | if (this.props.onRegionChangeComplete) { 94 | this.props.onRegionChangeComplete(region); 95 | } 96 | }; 97 | 98 | private clusterize = () => { 99 | const { superClusterOptions, region, children } = this.props; 100 | clusterService.createClusters(superClusterOptions, children); 101 | this.generateMarkers(region); 102 | }; 103 | 104 | private onClusterMarkerPress = (event: IClusterClickEvent) => { 105 | const { isClusterExpandClick, onClusterClick } = this.props; 106 | const { clusterId } = event; 107 | if (isClusterExpandClick) { 108 | const region = clusterService.expandCluster(clusterId); 109 | this.mapRef.animateToRegion(region, CLUSTER_EXPAND_TIME); 110 | } 111 | if (onClusterClick) { 112 | const clusterChildren = clusterService.getClusterChildren(clusterId); 113 | onClusterClick(event, clusterChildren); 114 | } 115 | }; 116 | 117 | private renderContent = () => { 118 | return this.renderMarkers().concat( 119 | utils.formatChildren(this.props.children, false) 120 | ); 121 | }; 122 | 123 | private renderMarkers = () => { 124 | const { markers } = this.state; 125 | const { renderClusterMarker, clusterMarkerProps } = this.props; 126 | 127 | return markers.map((marker) => { 128 | const { properties, geometry } = marker; 129 | const { cluster, element, point_count } = properties; 130 | const key = utils.makeId(); 131 | 132 | if (!cluster && element) { 133 | return element; 134 | } 135 | 136 | return ( 137 | 145 | {renderClusterMarker && renderClusterMarker({ 146 | pointCount: point_count, clusterId: marker.properties.cluster_id 147 | })} 148 | 149 | ); 150 | }); 151 | }; 152 | 153 | private onMapReady = () => { 154 | this.setState( 155 | { 156 | isMapLoaded: true, 157 | }, 158 | () => this.props.onMapReady && this.props.onMapReady() 159 | ); 160 | }; 161 | } 162 | 163 | const styles = StyleSheet.create({ 164 | map: { 165 | ...StyleSheet.absoluteFillObject, 166 | }, 167 | }); 168 | -------------------------------------------------------------------------------- /src/cluster-marker.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, Text, View } from 'react-native'; 3 | import { Marker, MapEvent } from 'react-native-maps'; 4 | 5 | import { IClusterMarkerProps, IMarkerEvent } from './typings'; 6 | 7 | export const ClusterMarker = (props: IClusterMarkerProps) => { 8 | const { 9 | coordinates, 10 | pointCount, 11 | children, 12 | onClusterMarkerPress, 13 | clusterId, 14 | clusterMarkerProps, 15 | } = props; 16 | 17 | if (pointCount < 0) { 18 | return null; 19 | } 20 | 21 | const onClusterPress = (e: MapEvent) => { 22 | const { coordinate } = e.nativeEvent; 23 | onClusterMarkerPress({ clusterId, coordinate }); 24 | }; 25 | const [longitude, latitude] = coordinates; 26 | 27 | return ( 28 | 33 | {children || ( 34 | 35 | {pointCount} 36 | 37 | )} 38 | 39 | ); 40 | }; 41 | 42 | const styles = StyleSheet.create({ 43 | clusterBox: { 44 | height: 60, 45 | width: 60, 46 | borderWidth: 2, 47 | borderColor: '#5694f7', 48 | backgroundColor: '#fff', 49 | borderRadius: 31, 50 | alignItems: 'center', 51 | justifyContent: 'center', 52 | }, 53 | clusterText: { 54 | fontSize: 19, 55 | color: '#5694f7', 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /src/cluster-service.ts: -------------------------------------------------------------------------------- 1 | import { ReactElement } from 'react'; 2 | import { Dimensions } from 'react-native'; 3 | import SuperCluster from 'supercluster'; 4 | 5 | import { Feature, Point, BBox, GeoJsonProperties } from 'geojson'; 6 | import { Region } from 'react-native-maps'; 7 | import { ICoords } from './typings'; 8 | import { calculateDelta, calculateAverage, formatChildren } from './utils'; 9 | 10 | const DEFAULT_SUPERCLUSTER_OPTIONS = { 11 | radius: 16, 12 | maxZoom: 15, 13 | minZoom: 1, 14 | nodeSize: 16, 15 | }; 16 | 17 | export const INCREASE_RATE = 2; 18 | 19 | export class ClusterService { 20 | private superCluster: SuperCluster = null; 21 | private markers: Array> = null; 22 | 23 | public createClusters( 24 | propsOptions: object, 25 | children: ReactElement[] | ReactElement 26 | ) { 27 | const options = propsOptions || DEFAULT_SUPERCLUSTER_OPTIONS; 28 | this.superCluster = new SuperCluster(options); 29 | this.markers = formatChildren(children, true).map( 30 | this.createGeoJsonFeature 31 | ); 32 | 33 | this.superCluster.load(this.markers); 34 | } 35 | 36 | public getCurrentZoom = (region: Region) => { 37 | const bBox = this.regionTobBox(region); 38 | return this.getBoundsZoomLevel(bBox); 39 | }; 40 | 41 | public getClusterChildren = (id: number) => { 42 | return this.superCluster.getLeaves(id); 43 | }; 44 | 45 | // TODO: Add unit test 46 | public getClustersOptions = (region: Region, currentZoom: null | number) => { 47 | const bBox = this.regionTobBox(region); 48 | const zoom = currentZoom || this.getBoundsZoomLevel(bBox); 49 | return { 50 | markers: this.superCluster.getClusters(bBox, zoom), 51 | zoom, 52 | }; 53 | }; 54 | // TODO: Add unit test 55 | public expandCluster = (clusterId: number): Region => { 56 | const clusterMarkersCoordinates = this.getClusterMarkers(clusterId).map( 57 | this.getMarkersCoordinates 58 | ); 59 | return this.getMarkersRegion(clusterMarkersCoordinates); 60 | }; 61 | 62 | private createGeoJsonFeature = (element: ReactElement): Feature => ({ 63 | type: 'Feature', 64 | geometry: { 65 | type: 'Point', 66 | coordinates: [ 67 | element.props.coordinate.longitude as number, 68 | element.props.coordinate.latitude as number, 69 | ], 70 | }, 71 | properties: { element }, 72 | }); 73 | 74 | // TODO: Add unit test 75 | private getBoundsZoomLevel = (bounds: BBox) => { 76 | const ZOOM_MAX = 20; 77 | const WORLD_DIM = this.getDimensions(); 78 | 79 | function latRad(lat: number) { 80 | const sin = Math.sin((lat * Math.PI) / 180); 81 | const radX2 = Math.log((1 + sin) / (1 - sin)) / 2; 82 | return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2; 83 | } 84 | 85 | function zoom(mapPx: number, worldPx: number, fraction: number) { 86 | return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2); 87 | } 88 | 89 | const latFraction = (latRad(bounds[3]) - latRad(bounds[1])) / Math.PI; 90 | const lngDiff = bounds[2] - bounds[0]; 91 | const lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360; 92 | const latZoom = zoom(WORLD_DIM.height, WORLD_DIM.height, latFraction); 93 | const lngZoom = zoom(WORLD_DIM.width, WORLD_DIM.width, lngFraction); 94 | return Math.min(latZoom, lngZoom, ZOOM_MAX); 95 | }; 96 | 97 | private regionTobBox = (region: Region): BBox => { 98 | const lngD = 99 | region.longitudeDelta < 0 100 | ? region.longitudeDelta + 360 101 | : region.longitudeDelta; 102 | 103 | return [ 104 | region.longitude - lngD, // westLng - min lng 105 | region.latitude - region.latitudeDelta, // southLat - min lat 106 | region.longitude + lngD, // eastLng - max lng 107 | region.latitude + region.latitudeDelta, // northLat - max lat 108 | ]; 109 | }; 110 | 111 | private getDimensions = () => { 112 | return { 113 | height: Dimensions.get('window').height, 114 | width: Dimensions.get('window').width, 115 | }; 116 | }; 117 | 118 | // TODO: Add unit test 119 | private getClusterMarkers = ( 120 | clusterId: number 121 | ): Array> => { 122 | const clusterChildren = this.superCluster.getChildren(clusterId); 123 | if (clusterChildren.length > 1) { 124 | return clusterChildren; 125 | } 126 | return this.getClusterMarkers(clusterChildren[0].id as number); 127 | }; 128 | 129 | private getMarkersRegion = (points: ICoords[]): Region => { 130 | const coordinates = { 131 | minX: points[0].latitude, 132 | maxX: points[0].latitude, 133 | maxY: points[0].longitude, 134 | minY: points[0].longitude, 135 | }; 136 | 137 | const { maxX, minX, maxY, minY } = points.reduce( 138 | (acc, point) => ({ 139 | minX: Math.min(acc.minX, point.latitude), 140 | maxX: Math.max(acc.maxX, point.latitude), 141 | minY: Math.min(acc.minY, point.longitude), 142 | maxY: Math.max(acc.maxY, point.longitude), 143 | }), 144 | { ...coordinates } 145 | ); 146 | 147 | const deltaX = calculateDelta(maxX, minX); 148 | const deltaY = calculateDelta(maxY, minY); 149 | 150 | return { 151 | latitude: calculateAverage(minX, maxX), 152 | longitude: calculateAverage(minY, maxY), 153 | latitudeDelta: deltaX * INCREASE_RATE, 154 | longitudeDelta: deltaY * INCREASE_RATE, 155 | }; 156 | }; 157 | 158 | private getMarkersCoordinates = (markers: Feature) => { 159 | const [longitude, latitude] = markers.geometry.coordinates; 160 | return { longitude, latitude }; 161 | }; 162 | } 163 | 164 | export const clusterService = new ClusterService(); 165 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cluster-map'; 2 | -------------------------------------------------------------------------------- /src/spec/cluster-service.test.ts: -------------------------------------------------------------------------------- 1 | import SuperCluster from 'supercluster'; 2 | 3 | import { ClusterService, INCREASE_RATE } from '../cluster-service'; 4 | import { MockFeature, generateMockCoords } from './mock.utils'; 5 | 6 | import { 7 | MOCKED_DEVICE_WIDTH, 8 | MOCKED_DEVICE_HEIGHT, 9 | mockedReactEl, 10 | mockedRegion, 11 | } from './mock.constants'; 12 | 13 | jest.mock('react-native', () => ({ 14 | Dimensions: { 15 | get: jest.fn().mockImplementation(() => ({ 16 | width: MOCKED_DEVICE_WIDTH, 17 | height: MOCKED_DEVICE_HEIGHT, 18 | })), 19 | }, 20 | })); 21 | 22 | describe('Service initialization', () => { 23 | let service: any = null as ClusterService; 24 | 25 | test('Cluster service init', () => { 26 | expect(service).toBeFalsy(); 27 | service = new ClusterService(); 28 | expect(service).toBeInstanceOf(ClusterService); 29 | }); 30 | 31 | test('ClusterService.createClusters init supercluster and markers', () => { 32 | expect(service.superCluster).toBeFalsy(); 33 | expect(service.markers).toBeFalsy(); 34 | 35 | service.createClusters({}, mockedReactEl); 36 | 37 | expect(service.superCluster).toBeInstanceOf(SuperCluster); 38 | expect(service.markers).toBeTruthy(); 39 | }); 40 | }); 41 | 42 | describe('Service utils', () => { 43 | const service: any = new ClusterService(); 44 | 45 | test('getMarkersCoordinates', () => { 46 | const longitude = 140; 47 | const latitude = 120; 48 | const Marker: any = new MockFeature({ longitude, latitude }, 1); 49 | 50 | const result = service.getMarkersCoordinates(Marker); 51 | 52 | expect(result).toHaveProperty('longitude', longitude); 53 | expect(result).toHaveProperty('latitude', latitude); 54 | }); 55 | 56 | test('getDimensions get mocked Dimensions', () => { 57 | const result = service.getDimensions(); 58 | expect(result).toHaveProperty('width', MOCKED_DEVICE_WIDTH); 59 | expect(result).toHaveProperty('height', MOCKED_DEVICE_HEIGHT); 60 | }); 61 | 62 | test('createGeoJsonFeature', () => { 63 | const expectedLongitude = 55; 64 | const expectedLatitude = 85; 65 | 66 | mockedReactEl.props.coordinate.longitude = expectedLongitude; 67 | mockedReactEl.props.coordinate.latitude = expectedLatitude; 68 | 69 | const result = service.createGeoJsonFeature(mockedReactEl); 70 | 71 | const { 72 | type, 73 | geometry: { type: GType, coordinates }, 74 | } = result; 75 | const [resLongitude, resLatitude] = coordinates; 76 | 77 | expect(type).toBeTruthy(); 78 | expect(type).toBe('Feature'); 79 | 80 | expect(GType).toBeTruthy(); 81 | expect(GType).toBe('Point'); 82 | 83 | expect(resLongitude).toBe(expectedLongitude); 84 | expect(resLatitude).toBe(expectedLatitude); 85 | }); 86 | 87 | 88 | test('getMarkersRegion', () => { 89 | const coordsListLength = 8; 90 | 91 | const minValue = 10; 92 | const maxValue = 10 * coordsListLength; 93 | 94 | const expectedLongitude = (minValue + maxValue) / 2; 95 | const expectedLatitude = (minValue + maxValue) / 2; 96 | const expectedDelta = (maxValue - minValue) * INCREASE_RATE; 97 | 98 | const mockedCoords = generateMockCoords(coordsListLength); 99 | const result = service.getMarkersRegion(mockedCoords); 100 | 101 | expect(result).toHaveProperty('latitude', expectedLatitude); 102 | expect(result).toHaveProperty('longitude', expectedLongitude); 103 | expect(result).toHaveProperty('latitudeDelta', expectedDelta); 104 | expect(result).toHaveProperty('longitudeDelta', expectedDelta); 105 | }); 106 | 107 | test('regionTobBox return array with length 4', () => { 108 | const result = service.regionTobBox(mockedRegion); 109 | expect(Array.isArray(result)).toBeTruthy(); 110 | expect(result).toHaveLength(4); 111 | }); 112 | }); 113 | -------------------------------------------------------------------------------- /src/spec/mock.constants.ts: -------------------------------------------------------------------------------- 1 | export const MOCKED_DEVICE_WIDTH = 375; 2 | export const MOCKED_DEVICE_HEIGHT = 800; 3 | 4 | export const mockedReactEl: any = { 5 | props: { coordinate: { longitude: 100, latitude: 120 } }, 6 | }; 7 | 8 | export const mockedRegion = { 9 | latitude: 37.78825, 10 | longitude: -122.4324, 11 | latitudeDelta: 0.0922, 12 | longitudeDelta: 0.0421, 13 | }; 14 | -------------------------------------------------------------------------------- /src/spec/mock.utils.ts: -------------------------------------------------------------------------------- 1 | import { LatLng } from 'react-native-maps'; 2 | 3 | export class MockFeature { 4 | public type: string; 5 | public geometry: any; 6 | public id: string; 7 | public properties: any; 8 | 9 | constructor(coordinate: LatLng, id: string | number, props?: {}) { 10 | this.type = 'Feature'; 11 | this.geometry = { 12 | type: 'Point', 13 | coordinates: [coordinate.longitude, coordinate.latitude], 14 | }; 15 | this.id = `Mocked marker ${id}`; 16 | this.properties = props; 17 | } 18 | } 19 | 20 | export function repeatElement(elem: any, count: number) { 21 | return new Array(count).fill(0).map((el) => elem); 22 | } 23 | 24 | export function generateMockCoords(count: number) { 25 | return new Array(count).fill(0).map((e, i) => ({ 26 | latitude: 10 * (i + 1), 27 | longitude: 10 * (i + 1), 28 | })); 29 | } 30 | -------------------------------------------------------------------------------- /src/spec/utils.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Marker, Circle } from 'react-native-maps'; 3 | 4 | import { 5 | makeId, 6 | serializeProps, 7 | calculateAverage, 8 | calculateDelta, 9 | formatChildren, 10 | } from '../utils'; 11 | 12 | import { mockedReactEl } from './mock.constants'; 13 | import { repeatElement } from './mock.utils'; 14 | 15 | describe('Make ID utils function', () => { 16 | test(`Generated id's length have to be 10`, () => { 17 | const generatedId = makeId(); 18 | expect(generatedId).toHaveLength(10); 19 | }); 20 | 21 | test(`Generated id's type have to be string`, () => { 22 | const generatedId = makeId(); 23 | expect(typeof generatedId).toBe('string'); 24 | }); 25 | }); 26 | 27 | describe('formatChildren utils function', () => { 28 | const props = { isOutsideCluster: true }; 29 | const children = [ 30 | , 31 | , 37 | , 42 | ]; 43 | test(`formatChildren should return markers`, () => { 44 | const res = formatChildren(children, true); 45 | 46 | expect(res).toHaveLength(1); 47 | expect(res[0]).toBe(children[0]); 48 | }); 49 | 50 | test(`formatChildren should return Polyline`, () => { 51 | const res = formatChildren(children, false); 52 | 53 | expect(res).toHaveLength(2); 54 | expect(res[0]).toBe(children[1]); 55 | expect(res[1]).toBe(children[2]); 56 | }); 57 | 58 | test('formatChildren should return array', () => { 59 | const result = formatChildren(mockedReactEl, true); 60 | 61 | const isArray = Array.isArray(result); 62 | expect(isArray).toBeTruthy(); 63 | expect(result).toHaveLength(1); 64 | 65 | const EXPECTED_LENGTH = 5; 66 | const mockedElemList = repeatElement(mockedReactEl, EXPECTED_LENGTH); 67 | 68 | const result1 = formatChildren(mockedElemList, true); 69 | const isArray1 = Array.isArray(result1); 70 | expect(isArray1).toBeTruthy(); 71 | expect(result1).toHaveLength(EXPECTED_LENGTH); 72 | }); 73 | }); 74 | 75 | describe('Serialize Props utils function', () => { 76 | const MOCKED_PROPS: any = { 77 | isClusterExpandClick: true, 78 | superClusterOptions: {}, 79 | region: { 80 | latitude: 0, 81 | longitude: 0, 82 | latitudeDelta: 0, 83 | longitudeDelta: 0, 84 | }, 85 | onZoomChange: jest.fn(), 86 | renderClusterMarker: jest.fn(), 87 | style: {}, 88 | onMapReady: jest.fn(), 89 | onClusterClick: jest.fn(), 90 | onRegionChangeComplete: jest.fn(), 91 | }; 92 | 93 | test(`function have to return empty object`, () => { 94 | const emptyObj: any = {}; 95 | 96 | expect(serializeProps(emptyObj)).toEqual(emptyObj); 97 | expect(serializeProps(MOCKED_PROPS)).toEqual(emptyObj); 98 | }); 99 | 100 | test(`function have to return filtered props`, () => { 101 | const expectedObject = { 102 | children: jest.fn(), 103 | }; 104 | 105 | const filteredProps = { 106 | ...MOCKED_PROPS, 107 | ...expectedObject, 108 | }; 109 | 110 | const serializedProps = serializeProps(filteredProps); 111 | expect(serializedProps).toEqual(expectedObject); 112 | }); 113 | }); 114 | 115 | test('calculate average works as expected', () => { 116 | const zero = calculateAverage(0); 117 | const three = calculateAverage(2, 4); 118 | const eleven = calculateAverage(5, 4, 11, 24); // 44 / 4 = 11 119 | 120 | expect(zero).toBe(0); 121 | expect(three).toBe(3); 122 | expect(eleven).toBe(11); 123 | }); 124 | 125 | test('calculateDelta works as expected', () => { 126 | const four = calculateDelta(6, 2); 127 | const four1 = calculateDelta(2, 6); 128 | expect(four).toBe(4); 129 | expect(four).toBe(four1); 130 | 131 | const randX = Math.random() * 10; 132 | const randY = Math.random() * 10; 133 | 134 | const result = calculateDelta(randX, randY); 135 | const result1 = calculateDelta(randY, randX); 136 | 137 | expect(result).toBe(result1); 138 | }); 139 | -------------------------------------------------------------------------------- /src/typings.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode, ReactElement } from 'react'; 2 | import { StyleProp, ViewStyle } from 'react-native'; 3 | import { LatLng, MapViewProps, Region, PROVIDER_GOOGLE, PROVIDER_DEFAULT } from 'react-native-maps'; 4 | import SuperCluster from 'supercluster'; 5 | 6 | export interface IClusterMapProps extends MapViewProps { 7 | isClusterExpandClick: boolean; 8 | superClusterOptions?: object; 9 | priorityMarker?: React.ReactElement; 10 | region: Region; 11 | children: ReactElement[] | ReactElement; 12 | style: StyleProp; 13 | onZoomChange?: (zoom: number) => void; 14 | renderClusterMarker: (renderClusterMarkerOptions: { pointCount: number, clusterId: number }) => ReactNode; 15 | onMapReady: () => void; 16 | onClusterClick: (clusterClickEvent?: IClusterClickEvent, 17 | clusterChildren?: Array> 18 | | Array>) => void; 19 | onRegionChangeComplete: (region: Region) => void; 20 | clusterMarkerProps?: object; 21 | provider: typeof PROVIDER_DEFAULT | typeof PROVIDER_GOOGLE; 22 | } 23 | 24 | export interface ICoords { 25 | latitude: number; 26 | longitude: number; 27 | } 28 | 29 | export interface IClusterMapState { 30 | markers: 31 | | Array> 32 | | Array>; 33 | isMapLoaded: boolean; 34 | currentZoom: null | number; 35 | } 36 | 37 | export interface IClusterClickEvent { 38 | clusterId: number; 39 | coordinate: LatLng; 40 | } 41 | 42 | export interface IClusterMarkerProps { 43 | coordinates: number[]; 44 | pointCount: number; 45 | children: ReactNode; 46 | clusterId: number; 47 | onClusterMarkerPress: (clusterClickEvent: IClusterClickEvent) => void; 48 | clusterMarkerProps?: object; 49 | } 50 | 51 | export interface IMarkerEvent { 52 | action: 'marker-press'; 53 | id: string; 54 | } 55 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { ReactElement } from 'react'; 2 | import { IClusterMapProps } from './typings'; 3 | 4 | const PACKAGE_PROPS = [ 5 | 'isClusterExpandClick', 6 | 'superClusterOptions', 7 | 'renderClusterMarker', 8 | 'style', 9 | 'onMapReady', 10 | 'onRegionChangeComplete', 11 | 'region', 12 | 'onClusterClick', 13 | 'priorityMarker', 14 | 'onZoomChange', 15 | ]; 16 | 17 | export const formatChildren = ( 18 | children: ReactElement[] | ReactElement, 19 | isInCluster: boolean 20 | ) => { 21 | if (!children) { 22 | return []; 23 | } 24 | 25 | const childrenList = !Array.isArray(children) ? [children] : children; 26 | 27 | return childrenList 28 | .flat(1) 29 | .filter((child: ReactElement) => 30 | isInCluster && child.props 31 | ? child.props.isOutsideCluster !== true 32 | : child.props.isOutsideCluster 33 | ); 34 | }; 35 | 36 | export const serializeProps = (userProps: IClusterMapProps) => { 37 | return Object.keys(userProps).reduce( 38 | (newProps, propKey: keyof IClusterMapProps) => { 39 | if (PACKAGE_PROPS.find((prop) => prop === propKey)) { 40 | return newProps; 41 | } 42 | return { ...newProps, [propKey]: userProps[propKey] }; 43 | }, 44 | {} 45 | ); 46 | }; 47 | 48 | export const makeId = () => { 49 | let id = ''; 50 | const possibleChar = 51 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 52 | for (let i = 0; i < 10; i++) { 53 | id += possibleChar.charAt(Math.floor(Math.random() * possibleChar.length)); 54 | } 55 | return id; 56 | }; 57 | 58 | export const calculateDelta = (x: number, y: number): number => 59 | x > y ? x - y : y - x; 60 | 61 | export const calculateAverage = (...args: number[]): number => { 62 | const argList = [...args]; 63 | if (!argList.length) { 64 | return 0; 65 | } 66 | 67 | return argList.reduce((sum, num: number) => sum + num, 0) / argList.length; 68 | }; 69 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "jsx": "react", 5 | "noImplicitAny": true, 6 | "declaration": true, 7 | "target": "es6", 8 | "noEmit": true, 9 | "allowSyntheticDefaultImports": true, 10 | "esModuleInterop": true, 11 | "lib": ["es2019"] 12 | }, 13 | "exclude": ["node_modules", "rollup.config.js", "example", "src/spec"] 14 | } 15 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended", 5 | "tslint-config-standard", 6 | "tslint-react", 7 | "tslint-config-prettier" 8 | ], 9 | "rules": { 10 | "ordered-imports": false, 11 | "object-literal-sort-keys": false, 12 | "member-ordering": [ 13 | true, 14 | { 15 | "order": [ 16 | "public-static-field", 17 | "protected-static-field", 18 | "private-static-field", 19 | 20 | "public-instance-field", 21 | "protected-instance-field", 22 | "private-instance-field", 23 | 24 | "public-instance-method", 25 | "protected-instance-method", 26 | "private-instance-method", 27 | 28 | "public-static-method", 29 | "protected-static-method", 30 | "private-static-method" 31 | ] 32 | } 33 | ], 34 | "jsx-no-lambda": true, 35 | "jsx-boolean-value": true 36 | }, 37 | "rulesDirectory": [] 38 | } 39 | --------------------------------------------------------------------------------