├── .circleci └── config.yml ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE.md └── workflows │ ├── radar-pre-release-actions.yml │ ├── radar-release-actions.yml │ └── update-native-sdks.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── MIGRATION.md ├── README.md ├── android ├── .npmignore ├── build.gradle ├── build.gradle.template ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── io │ └── radar │ └── react │ ├── RNRadarModule.java │ ├── RNRadarPackage.java │ ├── RNRadarReceiver.java │ ├── RNRadarUtils.java │ └── RNRadarVerifiedReceiver.java ├── app.plugin.js ├── babel.config.js ├── copyAssets.sh ├── example ├── .gitignore ├── App.tsx ├── app.json ├── assets │ ├── adaptive-icon.png │ ├── favicon.png │ ├── icon.png │ └── splash.png ├── babel.config.js ├── components │ └── exampleButton.js ├── eas.json ├── index.js ├── metro.config.js ├── package-lock.json ├── package.json └── tsconfig.json ├── hooks └── pre-commit ├── ios ├── .npmignore ├── Cartfile.private ├── Cartfile.resolved ├── Cartfile.resolved.template ├── RNRadar.h ├── RNRadar.m └── RNRadar.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ └── xcschemes │ └── RNRadar.xcscheme ├── logo.png ├── package-lock.json ├── package.json ├── plugin ├── src │ ├── index.ts │ ├── types.ts │ ├── withRadar.ts │ ├── withRadarAndroid.ts │ └── withRadarIOS.ts └── tsconfig.json ├── react-native-radar.podspec ├── react-native-radar.podspec.template ├── react-native.config.js ├── scripts ├── check-beta-tag.cjs └── check-latest-tag.cjs ├── src ├── @types │ ├── RadarNativeInterface.ts │ └── types.ts ├── helpers.js ├── index.native.ts ├── index.ts ├── index.web.js └── ui │ ├── autocomplete.jsx │ ├── back.png │ ├── close.png │ ├── images.js │ ├── map-logo.png │ ├── map.jsx │ ├── marker.png │ ├── radar-logo.png │ ├── search.png │ └── styles.js ├── test ├── index.test.js └── jest.setup.js └── tsconfig.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | orbs: 3 | macos: circleci/macos@2 4 | jobs: 5 | node: 6 | working_directory: ~/react-native-radar 7 | docker: 8 | - image: cimg/node:18.0 9 | steps: 10 | - checkout 11 | - run: npm install 12 | - run: npm install -g typescript 13 | - run: 14 | name: Test 15 | command: | 16 | mkdir -p test-results/jest 17 | npm run test 18 | environment: 19 | JEST_JUNIT_OUTPUT: test-results/jest/junit.xml 20 | - run: 21 | name: Type-check 22 | command: npm run build-all 23 | - persist_to_workspace: 24 | root: ~/react-native-radar 25 | paths: 26 | - android 27 | - ios 28 | - README.md 29 | - react-native-radar.podspec 30 | - dist 31 | - app.plugin.js 32 | - plugin/build 33 | - example 34 | - package.json 35 | - store_test_results: 36 | path: test-results 37 | - store_artifacts: 38 | path: test-results 39 | android: 40 | working_directory: ~/react-native-radar/example 41 | docker: 42 | - image: cimg/android:2024.01.1-browsers 43 | steps: 44 | - attach_workspace: 45 | at: ~/react-native-radar 46 | - run: 47 | name: Install Dependencies 48 | command: npm install 49 | - run: 50 | name: Install Radar from local path 51 | command: npm run install-radar-rebuild 52 | - run: sudo yarn global add react-native 53 | - run: 54 | name: Install Ninja 55 | command: | 56 | sudo apt-get update -o Acquire::AllowInsecureRepositories=true 57 | sudo apt-get install -y ninja-build 58 | - run: chown -R $USER:$USER android 59 | - run: cd android && ./gradlew 60 | ios: 61 | macos: 62 | xcode: "15.3.0" 63 | working_directory: ~/react-native-radar/example 64 | steps: 65 | - attach_workspace: 66 | at: ~/react-native-radar 67 | - run: 68 | name: Install Dependencies 69 | command: npm install 70 | - run: 71 | name: Install Radar from local path 72 | command: npm run install-radar-rebuild 73 | - run: cd ios 74 | - run: xcodebuild -workspace ios/Example.xcworkspace -scheme Example -sdk iphonesimulator 75 | 76 | 77 | workflows: 78 | version: 2 79 | node-android-ios: 80 | jobs: 81 | - node 82 | - android: 83 | requires: 84 | - node 85 | - ios: 86 | requires: 87 | - node 88 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "jest": true, 5 | "jest/globals": true 6 | }, 7 | "extends": "airbnb", 8 | "parser": "babel-eslint", 9 | "plugins": [ 10 | "react", 11 | "jest" 12 | ], 13 | "rules": { 14 | "consistent-return": 0, 15 | "func-names": 0, 16 | "global-require": 0, 17 | "max-len": 0, 18 | "no-alert": 0, 19 | "no-param-reassign": 0, 20 | "no-plusplus": 0, 21 | "no-shadow": 0, 22 | "no-throw-literal": 0, 23 | "no-underscore-dangle": 0, 24 | "no-unused-vars": ["error", { 25 | "argsIgnorePattern": "_", 26 | "varsIgnorePattern": "_" 27 | }], 28 | "object-curly-newline": 0, 29 | "operator-linebreak": 0, 30 | "prefer-destructuring": ["error", { 31 | "VariableDeclarator": { "array": false, "object": true }, 32 | "AssignmentExpression": { "array": false, "object": false } 33 | }], 34 | "react/jsx-one-expression-per-line": 0, 35 | "react/jsx-wrap-multilines": 0, 36 | "react/no-array-index-key": 0, 37 | "react/no-danger": 0, 38 | "react/prop-types": 0, 39 | "no-restricted-properties": [0, { 40 | "object": "Math", 41 | "property": "pow" 42 | }], 43 | "no-bitwise": 0, 44 | "padded-blocks": 0 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | ## Summary 8 | 9 | ## Code to reproduce 10 | 11 | ## Steps to reproduce 12 | 13 | ## OS version 14 | 15 | ## SDK installation method 16 | 17 | ## SDK version 18 | 19 | ## Other information 20 | -------------------------------------------------------------------------------- /.github/workflows/radar-pre-release-actions.yml: -------------------------------------------------------------------------------- 1 | name: Publish beta package to npmjs 2 | on: 3 | release: 4 | types: [ prereleased ] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | # Setup .npmrc file to publish to npm 11 | - uses: actions/setup-node@v2 12 | with: 13 | node-version: '16.x' 14 | registry-url: 'https://registry.npmjs.org' 15 | - run: npm ci 16 | - run: npm run check-beta-tag 17 | - run: npm run build 18 | - run: npm run copy-assets 19 | - run: npm run build-plugin 20 | - run: npm publish --tag beta 21 | env: 22 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/radar-release-actions.yml: -------------------------------------------------------------------------------- 1 | name: Publish latest package to npmjs 2 | on: 3 | release: 4 | types: [ released ] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | # Setup .npmrc file to publish to npm 11 | - uses: actions/setup-node@v2 12 | with: 13 | node-version: '16.x' 14 | registry-url: 'https://registry.npmjs.org' 15 | - run: npm ci 16 | - run: npm run check-latest-tag 17 | - run: npm run build 18 | - run: npm run copy-assets 19 | - run: npm run build-plugin 20 | - run: npm publish 21 | env: 22 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/update-native-sdks.yml: -------------------------------------------------------------------------------- 1 | # Bump Native SDK version numbers whenever a repository dispatch of a release 2 | # is received 3 | name: Bump Native SDKs 4 | on: 5 | repository_dispatch: 6 | types: ['ios-sdk-release', 'android-sdk-release'] 7 | jobs: 8 | update_android_sdk_version: 9 | runs-on: ubuntu-latest 10 | if: github.event.client_payload.platform == 'android' 11 | steps: 12 | - name: Event Information 13 | run: echo ${{ github.event.client_payload.release }} 14 | 15 | # checkout the repo 16 | - uses: actions/checkout@v2 17 | 18 | # copy the template file to its final destination 19 | - name: Copy android/build.gradle template file 20 | uses: canastro/copy-action@master 21 | with: 22 | source: 'android/build.gradle.template' 23 | target: 'android/build.gradle' 24 | 25 | # render the template using the input sdk version 26 | - name: Render radar-sdk-android release version onto build.gradle 27 | uses: jayamanikharyono/jinja-action@v0.1 28 | with: 29 | data: version=${{ github.event.client_payload.release }} 30 | path: 'android/build.gradle' 31 | 32 | # Update package.json to latest version 33 | - name: Update package.json to latest 34 | run: npm version ${{ github.event.client_payload.release }} --commit-hooks false --git-tag-version false 35 | 36 | # open a pull request with the new sdk version 37 | - name: Create Pull Request 38 | uses: peter-evans/create-pull-request@v3 39 | with: 40 | title: Automated radar-sdk-android version bump to ${{ github.event.client_payload.release }} 41 | reviewers: radarlabs/eng 42 | token: ${{ secrets.GITHUB_TOKEN }} 43 | update_ios_sdk_version: 44 | runs-on: ubuntu-latest 45 | if: github.event.client_payload.platform == 'ios' 46 | steps: 47 | - name: Event Information 48 | run: echo ${{ github.event.client_payload.release }} 49 | 50 | # checkout the repo 51 | - uses: actions/checkout@v2 52 | 53 | # copy the podspec template to its final destination 54 | - name: Copy the podspec template 55 | uses: canastro/copy-action@master 56 | with: 57 | source: 'react-native-radar.podspec.template' 58 | target: 'react-native-radar.podspec' 59 | 60 | # render the podspec template with the sdk version 61 | - name: Render radar-sdk-ios release version onto podspec template 62 | uses: jayamanikharyono/jinja-action@v0.1 63 | with: 64 | data: version=${{ github.event.client_payload.release }} 65 | path: 'react-native-radar.podspec' 66 | 67 | # copy the Cartfile template to its final destination 68 | - name: Copy ios/Cartfile.resolved template 69 | uses: canastro/copy-action@master 70 | with: 71 | source: 'ios/Cartfile.resolved.template' 72 | target: 'ios/Cartfile.resolved' 73 | 74 | # render the Cartfile template with the sdk version 75 | - name: Render radar-sdk-ios release version onto Cartfile template 76 | uses: jayamanikharyono/jinja-action@v0.1 77 | with: 78 | data: version=${{ github.event.client_payload.release }} 79 | path: 'ios/Cartfile.resolved' 80 | 81 | # Update package.json to latest version 82 | - name: Update package.json to latest 83 | run: npm version ${{ github.event.client_payload.release }} --commit-hooks false --git-tag-version false 84 | 85 | # open a pull request with the new sdk version 86 | - name: Create Pull Request 87 | uses: peter-evans/create-pull-request@v3 88 | with: 89 | title: Automated radar-sdk-ios version bump to ${{ github.event.client_payload.release }} 90 | reviewers: radarlabs/eng 91 | token: ${{ secrets.GITHUB_TOKEN }} 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/ 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | xcuserdata 12 | *.xccheckout 13 | **/*.xcworkspace 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | .gradle/ 19 | *.iml 20 | *.iws 21 | out/ 22 | local.properties 23 | node_modules/ 24 | npm-debug.log 25 | *.framework 26 | android/.project 27 | ios/Carthage/Checkouts 28 | ios/Carthage/Build 29 | junit.xml 30 | dist/ 31 | 32 | example2 33 | react-native-radar-*.tgz 34 | example/ios/ 35 | example/android/ 36 | junit.xml 37 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2019 Radar Labs, Inc. 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | # Migration guides 2 | 3 | ## 3.9.x to 3.10.0 4 | 5 | - Web support is no longer included in default export and is now a separate export `RadarRNWeb`. Call `import Radar, { RadarRNWeb } from 'react-native-radar'` 6 | 7 | ## 3.9.x to 3.9.2 8 | - On `options` for `autocompleteUI`, `threshold` is now `minCharacters`. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Radar](https://raw.githubusercontent.com/radarlabs/react-native-radar/master/logo.png) 2 | 3 | [![npm](https://img.shields.io/npm/v/react-native-radar.svg)](https://www.npmjs.com/package/react-native-radar) 4 | 5 | [Radar](https://radar.com) is the leading geofencing and location tracking platform. 6 | 7 | The Radar SDK abstracts away cross-platform differences between location services, allowing you to add geofencing, location tracking, trip tracking, geocoding, and search to your apps with just a few lines of code. 8 | 9 | ## Documentation 10 | 11 | See the Radar overview documentation [here](https://radar.com/documentation). 12 | 13 | Then, see the Radar React Native module documentation [here](https://radar.com/documentation/sdk/react-native). 14 | 15 | ## Examples 16 | 17 | See an example app in `example/`. 18 | 19 | Setup Radar public key check pre-commit hook with `cp -r hooks .git` to prevent accidental key leak when working with the Example app. 20 | 21 | To run example app with local `react-native-radar` dependency: 22 | 23 | - install node dependencies with `npm ci` and typescript if needed with `npm install -g typescript`. 24 | - build local `react-native-radar` with `npm run build-all`. 25 | - navigate to the example dir with `cd example`. 26 | - install node dependency of example with `npm ci`. 27 | - build native app using expo pre-build and `react-native-plugin` with `npm run install-radar-rebuild`. 28 | - run iOS and android example app with `npx expo run:ios` or `npx expo run:android`. 29 | 30 | 31 | ## Support 32 | 33 | Have questions? We're here to help! Email us at [support@radar.com](mailto:support@radar.com). 34 | -------------------------------------------------------------------------------- /android/.npmignore: -------------------------------------------------------------------------------- 1 | src/test/ 2 | build/ 3 | *.iml 4 | local.properties 5 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.0.3' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 31 16 | 17 | defaultConfig { 18 | minSdkVersion 16 19 | targetSdkVersion 31 20 | versionCode 1 21 | versionName '3.20.3' 22 | consumerProguardFiles 'proguard-rules.pro' 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | testOptions { 28 | unitTests.returnDefaultValues = true 29 | } 30 | configurations.all { 31 | resolutionStrategy { 32 | force 'androidx.core:core:1.6.0' 33 | force 'androidx.core:core-ktx:1.6.0' 34 | } 35 | } 36 | } 37 | 38 | repositories { 39 | mavenCentral() 40 | google() 41 | maven { 42 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 43 | url "$rootDir/../node_modules/react-native/android" 44 | } 45 | } 46 | 47 | dependencies { 48 | api 'com.facebook.react:react-native:+' 49 | api 'io.radar:sdk:3.21.3' 50 | } 51 | 52 | -------------------------------------------------------------------------------- /android/build.gradle.template: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.0.3' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 31 16 | 17 | defaultConfig { 18 | minSdkVersion 16 19 | targetSdkVersion 31 20 | versionCode 1 21 | versionName '{{ version }}' 22 | } 23 | lintOptions { 24 | abortOnError false 25 | } 26 | testOptions { 27 | unitTests.returnDefaultValues = true 28 | } 29 | configurations.all { 30 | resolutionStrategy { 31 | force 'androidx.core:core:1.6.0' 32 | force 'androidx.core:core-ktx:1.6.0' 33 | } 34 | } 35 | } 36 | 37 | repositories { 38 | mavenCentral() 39 | google() 40 | maven { 41 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 42 | url "$rootDir/../node_modules/react-native/android" 43 | } 44 | } 45 | 46 | dependencies { 47 | api 'com.facebook.react:react-native:+' 48 | api 'io.radar:sdk:{{ version }}' 49 | } 50 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.useAndroidX=true -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radarlabs/react-native-radar/cda65630b4b834233dda40c768c470325c171463/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jul 19 10:39:56 EDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -dontwarn com.huawei.** 2 | 3 | -dontwarn com.google.android.play.integrity.** 4 | -dontwarn com.google.android.play.core.integrity.** -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/src/main/java/io/radar/react/RNRadarPackage.java: -------------------------------------------------------------------------------- 1 | package io.radar.react; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.bridge.NativeModule; 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.uimanager.ViewManager; 11 | import com.facebook.react.bridge.JavaScriptModule; 12 | 13 | public class RNRadarPackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList(new RNRadarModule(reactContext)); 18 | } 19 | 20 | public List> createJSModules() { 21 | return Collections.emptyList(); 22 | } 23 | 24 | @Override 25 | public List createViewManagers(ReactApplicationContext reactContext) { 26 | return Collections.emptyList(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /android/src/main/java/io/radar/react/RNRadarReceiver.java: -------------------------------------------------------------------------------- 1 | package io.radar.react; 2 | 3 | import android.content.Context; 4 | import android.location.Location; 5 | import android.util.Log; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | import com.facebook.react.ReactApplication; 11 | import com.facebook.react.ReactInstanceManager; 12 | import com.facebook.react.ReactNativeHost; 13 | import com.facebook.react.bridge.Arguments; 14 | import com.facebook.react.bridge.ReactContext; 15 | import com.facebook.react.bridge.ReactMethod; 16 | import com.facebook.react.bridge.WritableMap; 17 | import com.facebook.react.modules.core.DeviceEventManagerModule; 18 | 19 | import io.radar.sdk.Radar; 20 | import io.radar.sdk.RadarReceiver; 21 | import io.radar.sdk.model.RadarEvent; 22 | import io.radar.sdk.model.RadarUser; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | 25 | public class RNRadarReceiver extends RadarReceiver { 26 | 27 | private ReactNativeHost reactNativeHost; 28 | private static final String TAG = "RNRadarReceiver"; 29 | protected boolean hasListeners = false; 30 | 31 | private void sendEvent(final String eventName, final Object data) { 32 | final ReactInstanceManager reactInstanceManager = reactNativeHost.getReactInstanceManager(); 33 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 34 | if (reactContext != null && hasListeners) { 35 | reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, data); 36 | } 37 | } 38 | 39 | @Override 40 | public void onEventsReceived(@NonNull Context context, @NonNull RadarEvent[] events, @Nullable RadarUser user) { 41 | try { 42 | ReactApplication reactApplication = ((ReactApplication)context.getApplicationContext()); 43 | reactNativeHost = reactApplication.getReactNativeHost(); 44 | 45 | WritableMap map = Arguments.createMap(); 46 | map.putArray("events", RNRadarUtils.arrayForJson(RadarEvent.toJson(events))); 47 | if (user != null) { 48 | map.putMap("user", RNRadarUtils.mapForJson(user.toJson())); 49 | } 50 | 51 | sendEvent("events", map); 52 | } catch (Exception e) { 53 | Log.e(TAG, "Exception", e); 54 | } 55 | } 56 | 57 | @Override 58 | public void onLocationUpdated(@NonNull Context context, @NonNull Location location, @NonNull RadarUser user) { 59 | try { 60 | ReactApplication reactApplication = ((ReactApplication)context.getApplicationContext()); 61 | reactNativeHost = reactApplication.getReactNativeHost(); 62 | 63 | WritableMap map = Arguments.createMap(); 64 | map.putMap("location", RNRadarUtils.mapForJson(Radar.jsonForLocation(location))); 65 | map.putMap("user", RNRadarUtils.mapForJson(user.toJson())); 66 | 67 | sendEvent("location", map); 68 | } catch (Exception e) { 69 | Log.e(TAG, "Exception", e); 70 | } 71 | } 72 | 73 | @Override 74 | public void onClientLocationUpdated(@NonNull Context context, @NonNull Location location, boolean stopped, @NonNull Radar.RadarLocationSource source) { 75 | try { 76 | ReactApplication reactApplication = ((ReactApplication)context.getApplicationContext()); 77 | reactNativeHost = reactApplication.getReactNativeHost(); 78 | 79 | WritableMap map = Arguments.createMap(); 80 | map.putMap("location", RNRadarUtils.mapForJson(Radar.jsonForLocation(location))); 81 | map.putBoolean("stopped", stopped); 82 | map.putString("source", source.toString()); 83 | 84 | sendEvent("clientLocation", map); 85 | } catch (Exception e) { 86 | Log.e(TAG, "Exception", e); 87 | } 88 | } 89 | 90 | @Override 91 | public void onError(@NonNull Context context, @NonNull Radar.RadarStatus status) { 92 | try { 93 | ReactApplication reactApplication = ((ReactApplication)context.getApplicationContext()); 94 | reactNativeHost = reactApplication.getReactNativeHost(); 95 | 96 | sendEvent("error", status.toString()); 97 | } catch (Exception e) { 98 | Log.e(TAG, "Exception", e); 99 | } 100 | } 101 | 102 | @Override 103 | public void onLog(@NonNull Context context, @NonNull String message) { 104 | try { 105 | ReactApplication reactApplication = ((ReactApplication)context.getApplicationContext()); 106 | reactNativeHost = reactApplication.getReactNativeHost(); 107 | 108 | sendEvent("log", message); 109 | } catch (Exception e) { 110 | Log.e(TAG, "Exception", e); 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /android/src/main/java/io/radar/react/RNRadarUtils.java: -------------------------------------------------------------------------------- 1 | package io.radar.react; 2 | 3 | import com.facebook.react.bridge.ReadableArray; 4 | import com.facebook.react.bridge.ReadableMapKeySetIterator; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.HashMap; 8 | 9 | import org.json.JSONArray; 10 | import org.json.JSONException; 11 | import org.json.JSONObject; 12 | 13 | import com.facebook.react.bridge.ReadableMap; 14 | import com.facebook.react.bridge.WritableArray; 15 | import com.facebook.react.bridge.WritableMap; 16 | import com.facebook.react.bridge.WritableNativeArray; 17 | import com.facebook.react.bridge.WritableNativeMap; 18 | 19 | class RNRadarUtils { 20 | 21 | static WritableMap mapForJson(JSONObject obj) throws JSONException { 22 | if (obj == null) { 23 | return null; 24 | } 25 | 26 | WritableMap writableMap = new WritableNativeMap(); 27 | Iterator iterator = obj.keys(); 28 | while (iterator.hasNext()) { 29 | String key = iterator.next(); 30 | Object value = obj.get(key); 31 | if (value instanceof JSONObject) { 32 | writableMap.putMap(key, mapForJson((JSONObject)value)); 33 | } else if (value instanceof JSONArray) { 34 | writableMap.putArray(key, arrayForJson((JSONArray)value)); 35 | } else if (value instanceof Boolean) { 36 | writableMap.putBoolean(key, (Boolean)value); 37 | } else if (value instanceof Integer) { 38 | writableMap.putInt(key, (Integer)value); 39 | } else if (value instanceof Double) { 40 | writableMap.putDouble(key, (Double)value); 41 | } else if (value instanceof Float) { 42 | String valueStr = value.toString(); 43 | Double valueDouble = Double.valueOf(valueStr); 44 | writableMap.putDouble(key, valueDouble); 45 | } else if (value instanceof String) { 46 | writableMap.putString(key, (String)value); 47 | } 48 | } 49 | return writableMap; 50 | } 51 | 52 | static WritableArray arrayForJson(JSONArray arr) throws JSONException { 53 | if (arr == null) { 54 | return null; 55 | } 56 | 57 | WritableArray writableArr = new WritableNativeArray(); 58 | for (int i = 0; i < arr.length(); i++) { 59 | Object value = arr.get(i); 60 | if (value instanceof JSONObject) { 61 | writableArr.pushMap(mapForJson((JSONObject)value)); 62 | } else if (value instanceof JSONArray) { 63 | writableArr.pushArray(arrayForJson((JSONArray)value)); 64 | } else if (value instanceof Boolean) { 65 | writableArr.pushBoolean((Boolean)value); 66 | } else if (value instanceof Integer) { 67 | writableArr.pushInt((Integer)value); 68 | } else if (value instanceof Double) { 69 | writableArr.pushDouble((Double)value); 70 | } else if (value instanceof String) { 71 | writableArr.pushString((String)value); 72 | } 73 | } 74 | return writableArr; 75 | } 76 | 77 | static JSONObject jsonForMap(ReadableMap readableMap) throws JSONException { 78 | if (readableMap == null) { 79 | return null; 80 | } 81 | 82 | JSONObject obj = new JSONObject(); 83 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); 84 | while (iterator.hasNextKey()) { 85 | String key = iterator.nextKey(); 86 | switch (readableMap.getType(key)) { 87 | case Null: 88 | obj.put(key, JSONObject.NULL); 89 | break; 90 | case Boolean: 91 | obj.put(key, readableMap.getBoolean(key)); 92 | break; 93 | case Number: 94 | obj.put(key, readableMap.getDouble(key)); 95 | break; 96 | case String: 97 | obj.put(key, readableMap.getString(key)); 98 | break; 99 | case Map: 100 | obj.put(key, jsonForMap(readableMap.getMap(key))); 101 | break; 102 | case Array: 103 | obj.put(key, jsonForArray(readableMap.getArray(key))); 104 | break; 105 | } 106 | } 107 | return obj; 108 | } 109 | 110 | static JSONArray jsonForArray(ReadableArray readableArr) throws JSONException { 111 | if (readableArr == null) { 112 | return null; 113 | } 114 | 115 | JSONArray arr = new JSONArray(); 116 | for (int i = 0; i < readableArr.size(); i++) { 117 | switch (readableArr.getType(i)) { 118 | case Null: 119 | break; 120 | case Boolean: 121 | arr.put(readableArr.getBoolean(i)); 122 | break; 123 | case Number: 124 | arr.put(readableArr.getDouble(i)); 125 | break; 126 | case String: 127 | arr.put(readableArr.getString(i)); 128 | break; 129 | case Map: 130 | arr.put(jsonForMap(readableArr.getMap(i))); 131 | break; 132 | case Array: 133 | arr.put(jsonForArray(readableArr.getArray(i))); 134 | break; 135 | } 136 | } 137 | return arr; 138 | } 139 | 140 | static String[] stringArrayForArray(ReadableArray readableArr) { 141 | String[] arr; 142 | if (readableArr != null) { 143 | int size = readableArr.size(); 144 | arr = new String[size]; 145 | for (int i = 0; i < size; i++) { 146 | arr[i] = readableArr.getString(i); 147 | } 148 | } else { 149 | arr = new String[0]; 150 | } 151 | return arr; 152 | } 153 | static Map stringStringMap(ReadableMap readableMap) { 154 | if (readableMap == null) { 155 | return null; 156 | } 157 | 158 | Map stringMap = new HashMap(); 159 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); 160 | while (iterator.hasNextKey()) { 161 | String key = iterator.nextKey(); 162 | stringMap.put(key, readableMap.getString(key)); 163 | } 164 | return stringMap; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /android/src/main/java/io/radar/react/RNRadarVerifiedReceiver.java: -------------------------------------------------------------------------------- 1 | package io.radar.react; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.facebook.react.ReactApplication; 9 | import com.facebook.react.ReactInstanceManager; 10 | import com.facebook.react.ReactNativeHost; 11 | import com.facebook.react.bridge.Arguments; 12 | import com.facebook.react.bridge.ReactContext; 13 | import com.facebook.react.bridge.ReactMethod; 14 | import com.facebook.react.bridge.WritableMap; 15 | import com.facebook.react.modules.core.DeviceEventManagerModule; 16 | 17 | import io.radar.sdk.Radar; 18 | import io.radar.sdk.RadarVerifiedReceiver; 19 | import io.radar.sdk.model.RadarVerifiedLocationToken; 20 | 21 | public class RNRadarVerifiedReceiver extends RadarVerifiedReceiver { 22 | 23 | private ReactNativeHost reactNativeHost; 24 | private static final String TAG = "RNRadarVerifiedReceiver"; 25 | protected boolean hasListeners = false; 26 | 27 | private void sendEvent(final String eventName, final Object data) { 28 | final ReactInstanceManager reactInstanceManager = reactNativeHost.getReactInstanceManager(); 29 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 30 | if (reactContext != null && hasListeners) { 31 | reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, data); 32 | } 33 | } 34 | 35 | @Override 36 | public void onTokenUpdated(@NonNull Context context, @NonNull RadarVerifiedLocationToken token) { 37 | try { 38 | ReactApplication reactApplication = ((ReactApplication)context.getApplicationContext()); 39 | reactNativeHost = reactApplication.getReactNativeHost(); 40 | 41 | sendEvent("token", RNRadarUtils.mapForJson(token.toJson())); 42 | } catch (Exception e) { 43 | Log.e(TAG, "Exception", e); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./plugin/build'); -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | const presets = [ 4 | '@babel/preset-env', 5 | '@babel/preset-react', 6 | 'module:metro-react-native-babel-preset', 7 | ]; 8 | return { 9 | presets, 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /copyAssets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source_dir="./src/ui" 4 | target_dir="./dist/ui" 5 | 6 | for file in "$source_dir"/*.png 7 | do 8 | cp "$file" "$target_dir" 9 | done -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | 11 | # Native 12 | *.orig.* 13 | *.jks 14 | *.p8 15 | *.p12 16 | *.key 17 | *.mobileprovision 18 | 19 | # Metro 20 | .metro-health-check* 21 | 22 | # debug 23 | npm-debug.* 24 | yarn-debug.* 25 | yarn-error.* 26 | 27 | # macOS 28 | .DS_Store 29 | *.pem 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { StyleSheet, Text, View, ScrollView, Platform } from "react-native"; 3 | import Radar, { 4 | Map, 5 | Autocomplete, 6 | RadarClientLocationUpdate, 7 | RadarLocationUpdate, 8 | RadarEventUpdate, 9 | } from "react-native-radar"; 10 | import MapLibreGL from "@maplibre/maplibre-react-native"; 11 | import ExampleButton from "./components/exampleButton"; 12 | 13 | // The current version of MapLibre does not support the new react native architecture 14 | MapLibreGL.setAccessToken(null); 15 | 16 | const stringify = (obj: any) => JSON.stringify(obj, null, 2); 17 | 18 | Radar.on("events", (result: RadarEventUpdate) => { 19 | console.log("events:", stringify(result)); 20 | }); 21 | 22 | Radar.on("location", (result: RadarLocationUpdate) => { 23 | console.log("location:", stringify(result)); 24 | }); 25 | 26 | Radar.on("clientLocation", (result: RadarClientLocationUpdate) => { 27 | console.log("clientLocation:", stringify(result)); 28 | }); 29 | 30 | Radar.on("error", (err: any) => { 31 | console.log("error:", stringify(err)); 32 | }); 33 | 34 | Radar.on("log", (result: string) => { 35 | console.log("log:", stringify(result)); 36 | }); 37 | 38 | export default function App() { 39 | // add in your test code here! 40 | const [displayText, setDisplayText] = useState(""); 41 | 42 | const handlePopulateText = (displayText: string) => { 43 | setDisplayText(displayText); 44 | }; 45 | Radar.initialize( 46 | "prj_test_pk_0000000000000000000000000000000000000000", 47 | true 48 | ); 49 | 50 | useEffect(() => { 51 | Radar.setLogLevel("debug"); 52 | 53 | Radar.setUserId("foo"); 54 | 55 | Radar.setDescription("description"); 56 | 57 | Radar.setMetadata({ 58 | foo: "bar", 59 | baz: true, 60 | qux: 1, 61 | }); 62 | }, []); 63 | 64 | return ( 65 | 66 | {/* The current version of MapLibre does not support the new react native architecture */} 67 | {Platform.OS !== "web" && ( 68 | <> 69 | 70 | 71 | 72 | 73 | 81 | 82 | 83 | )} 84 | 90 | 91 | {displayText} 92 | 93 | 94 | { 97 | Radar.getUserId() 98 | .then((result) => { 99 | handlePopulateText("getUserId:" + result); 100 | }) 101 | .catch((err) => { 102 | handlePopulateText("getUserId:" + err); 103 | }); 104 | }} 105 | /> 106 | { 109 | Radar.getDescription() 110 | .then((result) => { 111 | handlePopulateText("getDescription:" + result); 112 | }) 113 | .catch((err) => { 114 | handlePopulateText("getDescription:" + err); 115 | }); 116 | }} 117 | /> 118 | { 121 | Radar.getMetadata() 122 | .then((result) => { 123 | handlePopulateText("getMetadata:" + stringify(result)); 124 | }) 125 | .catch((err) => { 126 | handlePopulateText("getMetadata:" + err); 127 | }); 128 | }} 129 | /> 130 | { 133 | Radar.requestPermissions(false) 134 | .then((result) => { 135 | handlePopulateText("requestPermissions:" + result); 136 | }) 137 | .catch((err) => { 138 | handlePopulateText("requestPermissions:" + err); 139 | }); 140 | }} 141 | /> 142 | 143 | { 146 | Radar.requestPermissions(true) 147 | .then((result) => { 148 | handlePopulateText("requestPermissions:" + result); 149 | }) 150 | .catch((err) => { 151 | handlePopulateText("requestPermissions:" + err); 152 | }); 153 | }} 154 | /> 155 | { 158 | Radar.getPermissionsStatus() 159 | .then((result) => { 160 | handlePopulateText("getPermissionsStatus:" + result); 161 | }) 162 | .catch((err) => { 163 | handlePopulateText("getPermissionsStatus:" + err); 164 | }); 165 | }} 166 | /> 167 | { 170 | Radar.getLocation() 171 | .then((result) => { 172 | handlePopulateText("getLocation:" + stringify(result)); 173 | }) 174 | .catch((err) => { 175 | handlePopulateText("getLocation:" + err); 176 | }); 177 | }} 178 | /> 179 | { 182 | Radar.trackOnce() 183 | .then((result) => { 184 | handlePopulateText("trackOnce:" + stringify(result)); 185 | }) 186 | .catch((err) => { 187 | handlePopulateText("trackOnce:" + err); 188 | }); 189 | }} 190 | /> 191 | 192 | { 195 | Radar.trackOnce({ 196 | location: { 197 | latitude: 39.2904, 198 | longitude: -76.6122, 199 | accuracy: 60, 200 | }, 201 | }) 202 | .then((result) => { 203 | handlePopulateText( 204 | "trackOnce manual with location accuracy::" + 205 | stringify(result) 206 | ); 207 | }) 208 | .catch((err) => { 209 | handlePopulateText( 210 | "trackOnce manual with location accuracy::" + err 211 | ); 212 | }); 213 | }} 214 | /> 215 | { 218 | Radar.trackOnce({ 219 | desiredAccuracy: "medium", 220 | beacons: true, 221 | }) 222 | .then((result) => { 223 | handlePopulateText( 224 | "trackOnce manual with beacons:" + stringify(result) 225 | ); 226 | }) 227 | .catch((err) => { 228 | handlePopulateText("trackOnce manual with beacons:" + err); 229 | }); 230 | }} 231 | /> 232 | { 235 | Radar.trackOnce({ 236 | latitude: 39.2904, 237 | longitude: -76.6122, 238 | accuracy: 65, 239 | }) 240 | .then((result) => { 241 | handlePopulateText( 242 | "trackOnce for back compatible:" + stringify(result) 243 | ); 244 | }) 245 | .catch((err) => { 246 | handlePopulateText("trackOnce for back compatible:" + err); 247 | }); 248 | }} 249 | /> 250 | 251 | { 254 | Radar.searchPlaces({ 255 | near: { 256 | latitude: 40.783826, 257 | longitude: -73.975363, 258 | }, 259 | radius: 1000, 260 | chains: ["starbucks"], 261 | chainMetadata: { 262 | customFlag: "true", 263 | }, 264 | countryCodes: ["CA", "US"], 265 | limit: 10, 266 | }) 267 | .then((result) => { 268 | handlePopulateText("searchPlaces:" + stringify(result)); 269 | }) 270 | .catch((err) => { 271 | handlePopulateText("searchPlaces:" + err); 272 | }); 273 | }} 274 | /> 275 | 276 | { 279 | Radar.searchGeofences({ 280 | radius: 1000, 281 | tags: ["venue"], 282 | limit: 10, 283 | includeGeometry: true, 284 | }) 285 | .then((result) => { 286 | handlePopulateText("searchGeofences:" + stringify(result)); 287 | }) 288 | .catch((err) => { 289 | handlePopulateText("searchGeofences:" + err); 290 | }); 291 | }} 292 | /> 293 | 294 | { 297 | Radar.autocomplete({ 298 | query: "brooklyn roasting", 299 | limit: 10, 300 | }) 301 | .then((result) => { 302 | handlePopulateText("autocomplete:" + stringify(result)); 303 | }) 304 | .catch((err) => { 305 | handlePopulateText("autocomplete:" + err); 306 | }); 307 | }} 308 | /> 309 | 310 | { 313 | Radar.geocode({ address: "20 jay st brooklyn" }) 314 | .then((result) => { 315 | handlePopulateText("geocode:" + stringify(result)); 316 | }) 317 | .catch((err) => { 318 | handlePopulateText("geocode:" + err); 319 | }); 320 | }} 321 | /> 322 | 323 | { 326 | Radar.reverseGeocode({ 327 | location: { 328 | latitude: 40.783826, 329 | longitude: -73.975363, 330 | }, 331 | }) 332 | .then((result) => { 333 | handlePopulateText("reverseGeocode:" + stringify(result)); 334 | }) 335 | .catch((err) => { 336 | handlePopulateText("reverseGeocode:" + err); 337 | }); 338 | }} 339 | /> 340 | 341 | { 344 | Radar.ipGeocode() 345 | .then((result) => { 346 | handlePopulateText("ipGeocode:" + stringify(result)); 347 | }) 348 | .catch((err) => { 349 | handlePopulateText("ipGeocode:" + err); 350 | }); 351 | }} 352 | /> 353 | 354 | { 357 | Radar.validateAddress({ 358 | latitude: 0, 359 | longitude: 0, 360 | city: "New York", 361 | stateCode: "NY", 362 | postalCode: "10003", 363 | countryCode: "US", 364 | street: "Broadway", 365 | number: "841", 366 | }) 367 | .then((result) => { 368 | handlePopulateText("validateAddress:" + stringify(result)); 369 | }) 370 | .catch((err) => { 371 | handlePopulateText("validateAddress:" + err); 372 | }); 373 | }} 374 | /> 375 | 376 | { 379 | Radar.getDistance({ 380 | origin: { 381 | latitude: 40.78382, 382 | longitude: -73.97536, 383 | }, 384 | destination: { 385 | latitude: 40.7039, 386 | longitude: -73.9867, 387 | }, 388 | modes: ["foot", "car"], 389 | units: "imperial", 390 | }) 391 | .then((result) => { 392 | handlePopulateText("getDistance:" + stringify(result)); 393 | }) 394 | .catch((err) => { 395 | handlePopulateText("getDistance:" + err); 396 | }); 397 | }} 398 | /> 399 | 400 | { 403 | Radar.getMatrix({ 404 | origins: [ 405 | { 406 | latitude: 40.78382, 407 | longitude: -73.97536, 408 | }, 409 | { 410 | latitude: 40.7039, 411 | longitude: -73.9867, 412 | }, 413 | ], 414 | destinations: [ 415 | { 416 | latitude: 40.64189, 417 | longitude: -73.78779, 418 | }, 419 | { 420 | latitude: 35.99801, 421 | longitude: -78.94294, 422 | }, 423 | ], 424 | mode: "car", 425 | units: "imperial", 426 | }) 427 | .then((result) => { 428 | handlePopulateText("getMatrix:" + stringify(result)); 429 | }) 430 | .catch((err) => { 431 | handlePopulateText("getMatrix:" + err); 432 | }); 433 | }} 434 | /> 435 | 436 | { 439 | Radar.startTrip({ 440 | tripOptions: { 441 | externalId: "300", 442 | destinationGeofenceTag: "store", 443 | destinationGeofenceExternalId: "123", 444 | mode: "car", 445 | scheduledArrivalAt: new Date( 446 | "2023-10-10T12:20:30Z" 447 | ).getTime(), 448 | metadata: { 449 | "test-trip-meta": "test-trip-data", 450 | }, 451 | }, 452 | }) 453 | .then((result) => { 454 | handlePopulateText("startTrip:" + stringify(result)); 455 | }) 456 | .catch((err) => { 457 | handlePopulateText("startTrip:" + err); 458 | }); 459 | }} 460 | /> 461 | 462 | { 465 | Radar.startTrip({ 466 | tripOptions: { 467 | externalId: "302", 468 | destinationGeofenceTag: "store", 469 | destinationGeofenceExternalId: "123", 470 | mode: "car", 471 | scheduledArrivalAt: new Date( 472 | "2023-10-10T12:20:30Z" 473 | ).getTime(), 474 | }, 475 | trackingOptions: { 476 | desiredStoppedUpdateInterval: 30, 477 | fastestStoppedUpdateInterval: 30, 478 | desiredMovingUpdateInterval: 30, 479 | fastestMovingUpdateInterval: 30, 480 | desiredSyncInterval: 20, 481 | desiredAccuracy: "high", 482 | stopDuration: 0, 483 | stopDistance: 0, 484 | replay: "none", 485 | sync: "all", 486 | showBlueBar: true, 487 | useStoppedGeofence: false, 488 | stoppedGeofenceRadius: 0, 489 | useMovingGeofence: false, 490 | movingGeofenceRadius: 0, 491 | syncGeofences: false, 492 | syncGeofencesLimit: 0, 493 | beacons: false, 494 | foregroundServiceEnabled: false, 495 | }, 496 | }) 497 | .then((result) => { 498 | handlePopulateText("startTrip:" + stringify(result)); 499 | }) 500 | .catch((err) => { 501 | handlePopulateText("startTrip:" + err); 502 | }); 503 | }} 504 | /> 505 | 506 | { 509 | Radar.completeTrip() 510 | .then((result) => { 511 | handlePopulateText("completeTrip:" + stringify(result)); 512 | }) 513 | .catch((err) => { 514 | handlePopulateText("completeTrip:" + err); 515 | }); 516 | }} 517 | /> 518 | 519 | { 522 | Radar.logConversion({ 523 | name: "in_app_purchase", 524 | revenue: 150, 525 | metadata: { 526 | sku: "123456789", 527 | }, 528 | }) 529 | .then((result) => { 530 | handlePopulateText("logConversion:" + stringify(result)); 531 | }) 532 | .catch((err) => { 533 | handlePopulateText("logConversion:" + err); 534 | }); 535 | }} 536 | /> 537 | 538 | { 541 | Radar.logConversion({ 542 | name: "in_app_purchase", 543 | metadata: { 544 | sku: "123456789", 545 | }, 546 | }) 547 | .then((result) => { 548 | handlePopulateText("logConversion:" + stringify(result)); 549 | }) 550 | .catch((err) => { 551 | handlePopulateText("logConversion:" + err); 552 | }); 553 | }} 554 | /> 555 | 556 | { 559 | Radar.trackVerified() 560 | .then((result) => { 561 | handlePopulateText("trackVerified:" + stringify(result)); 562 | }) 563 | .catch((err) => { 564 | handlePopulateText("trackVerified:" + err); 565 | }); 566 | }} 567 | /> 568 | 569 | { 572 | Radar.startTrackingVerified(); 573 | }} 574 | /> 575 | 576 | { 579 | Radar.isTrackingVerified() 580 | .then((result) => { 581 | handlePopulateText("isTrackingVerified:" + stringify(result)); 582 | }) 583 | .catch((err) => { 584 | handlePopulateText("isTrackingVerified:" + err); 585 | }); 586 | }} 587 | /> 588 | 589 | { 592 | Radar.stopTrackingVerified(); 593 | }} 594 | /> 595 | 596 | { 599 | Radar.setProduct("test"); 600 | }} 601 | /> 602 | 603 | { 606 | Radar.getVerifiedLocationToken() 607 | .then((result) => { 608 | handlePopulateText( 609 | "getVerifiedLocationToken:" + stringify(result) 610 | ); 611 | }) 612 | .catch((err) => { 613 | handlePopulateText("getVerifiedLocationToken:" + err); 614 | }); 615 | }} 616 | /> 617 | 618 | { 621 | Radar.nativeSdkVersion().then((nativeVersion) => { 622 | handlePopulateText( 623 | `sdk: ${Radar.rnSdkVersion()}, native: ${nativeVersion}` 624 | ); 625 | }); 626 | }} 627 | /> 628 | 629 | 630 | 631 | ); 632 | } 633 | 634 | const styles = StyleSheet.create({ 635 | container: { 636 | flex: 1, 637 | backgroundColor: "#fff", 638 | alignItems: "center", 639 | justifyContent: "center", 640 | }, 641 | displayText: { 642 | flex: 1, 643 | }, 644 | }); 645 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "Example", 4 | "slug": "Example", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "assetBundlePatterns": [ 15 | "**/*" 16 | ], 17 | "owner": "radarlabs", 18 | "ios": { 19 | "supportsTablet": true, 20 | "bundleIdentifier": "com.radar.reactnative.example" 21 | }, 22 | "android": { 23 | "adaptiveIcon": { 24 | "foregroundImage": "./assets/adaptive-icon.png", 25 | "backgroundColor": "#ffffff" 26 | }, 27 | "package": "com.radar.reactnative.example", 28 | "permissions": [ 29 | "android.permission.ACCESS_BACKGROUND_LOCATION", 30 | "android.permission.FOREGROUND_SERVICE", 31 | "android.permission.FOREGROUND_SERVICE_LOCATION", 32 | "android.permission.ACTIVITY_RECOGNITION", 33 | "android.permission.ACCESS_FINE_LOCATION" 34 | ] 35 | }, 36 | "web": { 37 | "favicon": "./assets/favicon.png" 38 | }, 39 | "plugins": [ 40 | [ 41 | "react-native-radar", 42 | { 43 | "iosFraud": true, 44 | "iosNSLocationAlwaysAndWhenInUseUsageDescription": "test value", 45 | "iosBackgroundMode": true, 46 | "androidFraud": false, 47 | "androidBackgroundPermission": true, 48 | "addRadarSDKMotion": true, 49 | "androidActivityRecognition": true, 50 | "androidForegroundService": true 51 | } 52 | ], 53 | [ 54 | "@maplibre/maplibre-react-native" 55 | ], 56 | [ 57 | "expo-build-properties", 58 | { 59 | "ios": { 60 | "newArchEnabled": false 61 | }, 62 | "android": { 63 | "newArchEnabled": false, 64 | "enableProguardInReleaseBuilds": true, 65 | "enableShrinkResourcesInReleaseBuilds": true 66 | } 67 | } 68 | ] 69 | ], 70 | "extra": { 71 | "eas": { 72 | "projectId": "caf6acc9-b3c5-4d95-af29-fd017a05abb8" 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /example/assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radarlabs/react-native-radar/cda65630b4b834233dda40c768c470325c171463/example/assets/adaptive-icon.png -------------------------------------------------------------------------------- /example/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radarlabs/react-native-radar/cda65630b4b834233dda40c768c470325c171463/example/assets/favicon.png -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radarlabs/react-native-radar/cda65630b4b834233dda40c768c470325c171463/example/assets/icon.png -------------------------------------------------------------------------------- /example/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radarlabs/react-native-radar/cda65630b4b834233dda40c768c470325c171463/example/assets/splash.png -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /example/components/exampleButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button } from "react-native"; 3 | 4 | const ExampleButton = ({ title, onPress }) => { 5 | return