├── .editorconfig ├── .gitattributes ├── .github ├── actions │ └── setup │ │ └── action.yml └── workflows │ └── ci.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .watchmanconfig ├── .yarnrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── android ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── osmdroid │ ├── OsmMapCallout.java │ ├── OsmMapCalloutManager.java │ ├── OsmMapCircle.java │ ├── OsmMapCircleManager.java │ ├── OsmMapFeature.java │ ├── OsmMapFileTile.java │ ├── OsmMapFileTileManager.java │ ├── OsmMapManager.java │ ├── OsmMapMarker.java │ ├── OsmMapMarkerManager.java │ ├── OsmMapModule.java │ ├── OsmMapPolygon.java │ ├── OsmMapPolygonManager.java │ ├── OsmMapPolyline.java │ ├── OsmMapPolylineManager.java │ ├── OsmMapUrlTile.java │ ├── OsmMapUrlTileManager.java │ ├── OsmMapView.java │ ├── OsmRegionChangeEvent.java │ ├── OsmdroidPackage.java │ ├── overlays │ ├── InterceptDoubleTapOverlay.java │ └── InterceptScrollOverlay.java │ └── utils │ ├── FileUtil.java │ ├── ImageReadable.java │ ├── ImageReader.java │ ├── ImageUtil.java │ ├── LatLngBoundsUtils.java │ └── SizeReportingShadowNode.java ├── babel.config.js ├── docs ├── callout.md ├── circle.md ├── geojson.md ├── mapview.md ├── marker.md ├── polygon.md ├── polyline.md └── tiles.md ├── example ├── .bundle │ └── config ├── .node-version ├── .ruby-version ├── .watchmanconfig ├── Gemfile ├── android │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── osmdroidexample │ │ │ │ └── ReactNativeFlipper.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── osmdroidexample │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainApplication.java │ │ │ │ └── newarchitecture │ │ │ │ ├── MainApplicationReactNativeHost.java │ │ │ │ ├── components │ │ │ │ └── MainComponentsRegistry.java │ │ │ │ └── modules │ │ │ │ └── MainApplicationTurboModuleManagerDelegate.java │ │ │ ├── jni │ │ │ ├── CMakeLists.txt │ │ │ ├── MainApplicationModuleProvider.cpp │ │ │ ├── MainApplicationModuleProvider.h │ │ │ ├── MainApplicationTurboModuleManagerDelegate.cpp │ │ │ ├── MainApplicationTurboModuleManagerDelegate.h │ │ │ ├── MainComponentsRegistry.cpp │ │ │ ├── MainComponentsRegistry.h │ │ │ └── OnLoad.cpp │ │ │ └── res │ │ │ ├── drawable │ │ │ └── rn_edit_text_material.xml │ │ │ ├── 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 │ ├── .xcode.env │ ├── File.swift │ ├── OsmdroidExample-Bridging-Header.h │ ├── OsmdroidExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── OsmdroidExample.xcscheme │ ├── OsmdroidExample.xcworkspace │ │ └── contents.xcworkspacedata │ ├── OsmdroidExample │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── main.m │ ├── OsmdroidExampleTests │ │ ├── Info.plist │ │ └── OsmdroidExampleTests.m │ ├── Podfile │ └── Podfile.lock ├── metro.config.js ├── package.json ├── react-native.config.js ├── src │ └── App.tsx └── yarn.lock ├── images ├── circle.png ├── mapView.png ├── marker.png ├── polygon.png ├── polyline.png └── urlTile.png ├── lefthook.yml ├── package.json ├── scripts └── bootstrap.js ├── src ├── AnimatedRegion.ts ├── Geojson.tsx ├── MapCallout.tsx ├── MapCircle.tsx ├── MapMarker.tsx ├── MapMarkerNativeComponent.ts ├── MapPolygon.tsx ├── MapPolyline.tsx ├── MapUrlTile.tsx ├── MapView.tsx ├── MapView.types.ts ├── MapViewNativeComponent.ts ├── __tests__ │ └── index.test.tsx ├── decorateMapComponent.ts ├── index.ts ├── sharedTypes.ts └── sharedTypesInternal.ts ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup 2 | description: Setup Node.js and install dependencies 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: Setup Node.js 8 | uses: actions/setup-node@v3 9 | with: 10 | node-version-file: .nvmrc 11 | 12 | - name: Cache dependencies 13 | id: yarn-cache 14 | uses: actions/cache@v3 15 | with: 16 | path: | 17 | **/node_modules 18 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 19 | restore-keys: | 20 | ${{ runner.os }}-yarn- 21 | 22 | - name: Install dependencies 23 | if: steps.yarn-cache.outputs.cache-hit != 'true' 24 | run: | 25 | yarn install --cwd example --frozen-lockfile 26 | yarn install --frozen-lockfile 27 | shell: bash 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Setup 18 | uses: ./.github/actions/setup 19 | 20 | - name: Lint files 21 | run: yarn lint 22 | 23 | - name: Typecheck files 24 | run: yarn typecheck 25 | 26 | test: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | 32 | - name: Setup 33 | uses: ./.github/actions/setup 34 | 35 | - name: Run unit tests 36 | run: yarn test --maxWorkers=2 --coverage 37 | 38 | build: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v3 43 | 44 | - name: Setup 45 | uses: ./.github/actions/setup 46 | 47 | - name: Build package 48 | run: yarn prepack 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Expo 64 | .expo/ 65 | 66 | # Turborepo 67 | .turbo/ 68 | 69 | # generated by bob 70 | lib/ 71 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.18.1 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.md 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | [INSERT CONTACT METHOD]. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series of 87 | actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or permanent 94 | ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within the 114 | community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.1, available at 120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 127 | [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 131 | [Mozilla CoC]: https://github.com/mozilla/diversity 132 | [FAQ]: https://www.contributor-covenant.org/faq 133 | [translations]: https://www.contributor-covenant.org/translations 134 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome, no matter how large or small! 4 | 5 | We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./CODE_OF_CONDUCT.md). 6 | 7 | ## Development workflow 8 | 9 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package: 10 | 11 | ```sh 12 | yarn 13 | ``` 14 | 15 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development. 16 | 17 | While developing, you can run the [example app](/example/) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app. 18 | 19 | To start the packager: 20 | 21 | ```sh 22 | yarn example start 23 | ``` 24 | 25 | To run the example app on Android: 26 | 27 | ```sh 28 | yarn example android 29 | ``` 30 | 31 | To run the example app on iOS: 32 | 33 | ```sh 34 | yarn example ios 35 | ``` 36 | 37 | Make sure your code passes TypeScript and ESLint. Run the following to verify: 38 | 39 | ```sh 40 | yarn typecheck 41 | yarn lint 42 | ``` 43 | 44 | To fix formatting errors, run the following: 45 | 46 | ```sh 47 | yarn lint --fix 48 | ``` 49 | 50 | Remember to add tests for your change if possible. Run the unit tests by: 51 | 52 | ```sh 53 | yarn test 54 | ``` 55 | 56 | To edit the Objective-C or Swift files, open `example/ios/OsmdroidExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > react-native-osmdroid`. 57 | 58 | To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `react-native-osmdroid` under `Android`. 59 | 60 | 61 | ### Commit message convention 62 | 63 | We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages: 64 | 65 | - `fix`: bug fixes, e.g. fix crash due to deprecated method. 66 | - `feat`: new features, e.g. add new method to the module. 67 | - `refactor`: code refactor, e.g. migrate from class components to hooks. 68 | - `docs`: changes into documentation, e.g. add usage example for the module.. 69 | - `test`: adding or updating tests, e.g. add integration tests using detox. 70 | - `chore`: tooling changes, e.g. change CI config. 71 | 72 | Our pre-commit hooks verify that your commit message matches this format when committing. 73 | 74 | ### Linting and tests 75 | 76 | [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/) 77 | 78 | We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing. 79 | 80 | Our pre-commit hooks verify that the linter and tests pass when committing. 81 | 82 | ### Publishing to npm 83 | 84 | We use [release-it](https://github.com/release-it/release-it) to make it easier to publish new versions. It handles common tasks like bumping version based on semver, creating tags and releases etc. 85 | 86 | To publish new versions, run the following: 87 | 88 | ```sh 89 | yarn release 90 | ``` 91 | 92 | ### Scripts 93 | 94 | The `package.json` file contains various scripts for common tasks: 95 | 96 | - `yarn bootstrap`: setup project by installing all dependencies and pods. 97 | - `yarn typecheck`: type-check files with TypeScript. 98 | - `yarn lint`: lint files with ESLint. 99 | - `yarn test`: run unit tests with Jest. 100 | - `yarn example start`: start the Metro server for the example app. 101 | - `yarn example android`: run the example app on Android. 102 | - `yarn example ios`: run the example app on iOS. 103 | 104 | ### Sending a pull request 105 | 106 | > **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github). 107 | 108 | When you're sending a pull request: 109 | 110 | - Prefer small pull requests focused on one change. 111 | - Verify that linters and tests are passing. 112 | - Review the documentation to make sure it looks good. 113 | - Follow the pull request template when opening a pull request. 114 | - For pull requests that change the API or implementation, discuss with maintainers first by opening an issue. 115 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Nikita_Kovantsov 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-osmdroid [![npm version](https://img.shields.io/npm/v/@splicer97/react-native-osmdroid.svg?style=flat)](https://www.npmjs.com/package/@splicer97/react-native-osmdroid) [![Downloads](https://img.shields.io/npm/dm/@splicer97/react-native-osmdroid.svg)](http://www.npmtrends.com/@splicer97/react-native-osmdroid) 2 | 3 | React Native Open Street Maps components for Android. 4 | This is unofficial React Native wrapper for Osmdroid SDK. 5 | Many thanks to [fqborges](https://github.com/fqborges) for his [library](https://github.com/fqborges/react-native-maps-osmdroid), which is the basis of this library! 6 | ## Installation 7 | 8 | ```sh 9 | npm install @splicer97/react-native-osmdroid 10 | ``` 11 | 12 | or 13 | 14 | ```sh 15 | yarn add @splicer97/react-native-osmdroid 16 | ``` 17 | 18 | ## Manifest 19 | 20 | In most cases, you will have to set the following authorizations in your AndroidManifest.xml: 21 | 22 | ```sh 23 | 24 | 25 | 26 | 27 | ``` 28 | 29 | If you are only using parts of the library, you can adjust the permissions accordingly. 30 | 31 | Online tile provider 32 | 33 | ```sh 34 | 35 | 36 | ``` 37 | 38 | Offline tile provider and storing tiles 39 | 40 | ```sh 41 | 42 | ``` 43 | 44 | Location provider 45 | 46 | ```sh 47 | 48 | ``` 49 | 50 | Android 6.0+ devices require you have to check for "dangerous" permissions at runtime. 51 | osmdroid requires the following dangerous permissions: 52 | WRITE_EXTERNAL_STORAGE and ACCESS_COARSE_LOCATION/ACCESS_FINE_LOCATION. 53 | See [OpenStreetMapViewer's implementation](https://github.com/osmdroid/osmdroid/blob/master/OpenStreetMapViewer/src/main/java/org/osmdroid/MainActivity.java#L83) or [Google Documentation on Permissions](https://developer.android.com/training/permissions/requesting) 54 | 55 | ## Component API 56 | 57 | [`` Component API](docs/mapview.md) 58 | 59 | [`` Component API](docs/marker.md) 60 | 61 | [`` Component API](docs/callout.md) 62 | 63 | [`` Component API](docs/polygon.md) 64 | 65 | [`` Component API](docs/polyline.md) 66 | 67 | [`` Component API](docs/circle.md) 68 | 69 | [`` Component API](docs/overlay.md) 70 | 71 | [`` Component API](docs/heatmap.md) 72 | 73 | [`` Component API](docs/geojson.md) 74 | 75 | [`` and `` Component API](docs/tiles.md) 76 | 77 | ## Usage 78 | 79 | ```js 80 | import MapView from '@splicer97/react-native-osmdroid'; 81 | 82 | // ... 83 | ; 91 | ``` 92 | 93 | ## Examples 94 | ### MapView 95 | mapView 96 | 97 | ### Polyline 98 | polyline 99 | 100 | ### Marker 101 | marker 102 | 103 | ### Polygon 104 | polygon 105 | 106 | ### Circle 107 | circle 108 | 109 | ### UrlTile 110 | urlTile 111 | 112 | ## Contributing 113 | 114 | See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. 115 | 116 | ## License 117 | 118 | MIT 119 | 120 | --- 121 | 122 | Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 123 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath "com.android.tools.build:gradle:7.2.1" 9 | } 10 | } 11 | 12 | def isNewArchitectureEnabled() { 13 | return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" 14 | } 15 | 16 | apply plugin: "com.android.library" 17 | 18 | if (isNewArchitectureEnabled()) { 19 | apply plugin: "com.facebook.react" 20 | } 21 | 22 | def getExtOrDefault(name) { 23 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Osmdroid_" + name] 24 | } 25 | 26 | def getExtOrIntegerDefault(name) { 27 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Osmdroid_" + name]).toInteger() 28 | } 29 | 30 | android { 31 | compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") 32 | 33 | defaultConfig { 34 | minSdkVersion getExtOrIntegerDefault("minSdkVersion") 35 | targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") 36 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() 37 | } 38 | buildTypes { 39 | release { 40 | minifyEnabled false 41 | } 42 | } 43 | 44 | lintOptions { 45 | disable "GradleCompatible" 46 | } 47 | 48 | compileOptions { 49 | sourceCompatibility JavaVersion.VERSION_1_8 50 | targetCompatibility JavaVersion.VERSION_1_8 51 | } 52 | 53 | } 54 | 55 | repositories { 56 | repositories { 57 | maven { 58 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 59 | url("$rootDir/../node_modules/react-native/android") 60 | } 61 | maven { 62 | // Android JSC is installed from npm 63 | url("$rootDir/../node_modules/jsc-android/dist") 64 | } 65 | mavenCentral { 66 | // We don't want to fetch react-native from Maven Central as there are 67 | // older versions over there. 68 | content { 69 | excludeGroup "com.facebook.react" 70 | } 71 | } 72 | 73 | google() 74 | maven { url "https://maven.google.com" } 75 | maven { url 'https://www.jitpack.io' } 76 | } 77 | } 78 | 79 | 80 | dependencies { 81 | implementation "com.facebook.react:react-native:+" 82 | implementation "org.osmdroid:osmdroid-android:6.1.17" 83 | } 84 | 85 | if (isNewArchitectureEnabled()) { 86 | react { 87 | jsRootDir = file("../src/") 88 | libraryName = "OsmdroidView" 89 | codegenJavaPackageName = "com.osmdroid" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | Osmdroid_kotlinVersion=1.7.0 2 | Osmdroid_minSdkVersion=21 3 | Osmdroid_targetSdkVersion=31 4 | Osmdroid_compileSdkVersion=31 5 | Osmdroid_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /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 https://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 Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapCallout.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import com.facebook.react.views.view.ReactViewGroup; 5 | 6 | public class OsmMapCallout extends ReactViewGroup { 7 | private boolean tooltip = false; 8 | public int width; 9 | public int height; 10 | 11 | public OsmMapCallout(Context context) { 12 | super(context); 13 | } 14 | 15 | public void setTooltip(boolean tooltip) { 16 | this.tooltip = tooltip; 17 | } 18 | 19 | public boolean getTooltip() { 20 | return this.tooltip; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapCalloutManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.osmdroid.utils.SizeReportingShadowNode; 6 | import com.facebook.react.common.MapBuilder; 7 | import com.facebook.react.uimanager.LayoutShadowNode; 8 | import com.facebook.react.uimanager.ThemedReactContext; 9 | import com.facebook.react.uimanager.ViewGroupManager; 10 | import com.facebook.react.uimanager.annotations.ReactProp; 11 | 12 | import java.util.Map; 13 | 14 | import javax.annotation.Nullable; 15 | 16 | public class OsmMapCalloutManager extends ViewGroupManager { 17 | 18 | @Override 19 | public String getName() { 20 | return "OsmMapCallout"; 21 | } 22 | 23 | @Override 24 | public OsmMapCallout createViewInstance(@NonNull ThemedReactContext context) { 25 | return new OsmMapCallout(context); 26 | } 27 | 28 | @ReactProp(name = "tooltip", defaultBoolean = false) 29 | public void setTooltip(OsmMapCallout view, boolean tooltip) { 30 | view.setTooltip(tooltip); 31 | } 32 | 33 | @Override 34 | @Nullable 35 | public Map getExportedCustomDirectEventTypeConstants() { 36 | return MapBuilder.of("onPress", MapBuilder.of("registrationName", "onPress")); 37 | } 38 | 39 | @Override 40 | public LayoutShadowNode createShadowNodeInstance() { 41 | // we use a custom shadow node that emits the width/height of the view 42 | // after layout with the updateExtraData method. Without this, we can't generate 43 | // a bitmap of the appropriate width/height of the rendered view. 44 | return new SizeReportingShadowNode(); 45 | } 46 | 47 | @Override 48 | public void updateExtraData(OsmMapCallout view, Object extraData) { 49 | // This method is called from the shadow node with the width/height of the rendered 50 | // marker view. 51 | //noinspection unchecked 52 | Map data = (Map) extraData; 53 | float width = data.get("width"); 54 | float height = data.get("height"); 55 | view.width = (int) width; 56 | view.height = (int) height; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapCircle.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | 5 | import org.osmdroid.util.GeoPoint; 6 | import org.osmdroid.views.MapView; 7 | import org.osmdroid.views.overlay.Polygon; 8 | 9 | public class OsmMapCircle extends OsmMapFeature { 10 | 11 | private Polygon polygon; 12 | 13 | private GeoPoint center; 14 | private double radius; 15 | private int strokeColor; 16 | private int fillColor; 17 | private float strokeWidth; 18 | private MapView mapView; 19 | 20 | public OsmMapCircle(Context context) { 21 | super(context); 22 | } 23 | 24 | public void setCenter(GeoPoint center) { 25 | this.center = center; 26 | if (polygon != null) { 27 | polygon.setPoints(Polygon.pointsAsCircle(center, radius)); 28 | } 29 | } 30 | 31 | public void setRadius(double radius) { 32 | this.radius = radius; 33 | if (polygon != null) { 34 | polygon.setPoints(Polygon.pointsAsCircle(center, radius)); 35 | } 36 | } 37 | 38 | public void setFillColor(int color) { 39 | this.fillColor = color; 40 | if (polygon != null) { 41 | polygon.getFillPaint().setColor(color); 42 | mapView.invalidate(); 43 | } 44 | } 45 | 46 | public void setStrokeColor(int color) { 47 | this.strokeColor = color; 48 | if (polygon != null) { 49 | polygon.getOutlinePaint().setColor(color); 50 | mapView.invalidate(); 51 | } 52 | } 53 | 54 | public void setStrokeWidth(float width) { 55 | this.strokeWidth = width; 56 | if (polygon != null) { 57 | polygon.getOutlinePaint().setStrokeWidth(width); 58 | mapView.invalidate(); 59 | } 60 | } 61 | 62 | @Override 63 | public Object getFeature() { 64 | return polygon; 65 | } 66 | 67 | @Override 68 | public void addToMap(MapView map) { 69 | polygon = new Polygon(); 70 | mapView = map; 71 | polygon.setPoints(Polygon.pointsAsCircle(center, radius)); 72 | polygon.getFillPaint().setColor(fillColor); 73 | polygon.getOutlinePaint().setColor(strokeColor); 74 | polygon.getOutlinePaint().setStrokeWidth(strokeWidth); 75 | map.getOverlays().add(polygon); 76 | mapView.invalidate(); 77 | } 78 | 79 | @Override 80 | public void removeFromMap(MapView map) { 81 | map.getOverlays().remove(polygon); 82 | polygon = null; 83 | mapView = null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapCircleManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.util.DisplayMetrics; 7 | import android.view.WindowManager; 8 | 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.bridge.ReadableMap; 11 | import com.facebook.react.uimanager.ThemedReactContext; 12 | import com.facebook.react.uimanager.ViewGroupManager; 13 | import com.facebook.react.uimanager.annotations.ReactProp; 14 | 15 | import org.osmdroid.util.GeoPoint; 16 | 17 | public class OsmMapCircleManager extends ViewGroupManager { 18 | private final DisplayMetrics metrics; 19 | 20 | public OsmMapCircleManager(ReactApplicationContext reactContext) { 21 | super(); 22 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 23 | metrics = new DisplayMetrics(); 24 | ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE)) 25 | .getDefaultDisplay() 26 | .getRealMetrics(metrics); 27 | } else { 28 | metrics = reactContext.getResources().getDisplayMetrics(); 29 | } 30 | } 31 | 32 | @Override 33 | public String getName() { 34 | return "OsmMapCircle"; 35 | } 36 | 37 | @Override 38 | public OsmMapCircle createViewInstance(ThemedReactContext context) { 39 | return new OsmMapCircle(context); 40 | } 41 | 42 | @ReactProp(name = "center") 43 | public void setCenter(OsmMapCircle view, ReadableMap center) { 44 | view.setCenter(new GeoPoint(center.getDouble("latitude"), center.getDouble("longitude"))); 45 | } 46 | 47 | @ReactProp(name = "radius", defaultDouble = 0) 48 | public void setRadius(OsmMapCircle view, double radius) { 49 | view.setRadius(radius); 50 | } 51 | 52 | @ReactProp(name = "strokeWidth", defaultFloat = 1f) 53 | public void setStrokeWidth(OsmMapCircle view, float widthInPoints) { 54 | float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS 55 | view.setStrokeWidth(widthInScreenPx); 56 | } 57 | 58 | @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color") 59 | public void setFillColor(OsmMapCircle view, int color) { 60 | view.setFillColor(color); 61 | } 62 | 63 | @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color") 64 | public void setStrokeColor(OsmMapCircle view, int color) { 65 | view.setStrokeColor(color); 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapFeature.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | 5 | import com.facebook.react.views.view.ReactViewGroup; 6 | 7 | import org.osmdroid.views.MapView; 8 | 9 | public abstract class OsmMapFeature extends ReactViewGroup { 10 | public OsmMapFeature(Context context) { 11 | super(context); 12 | } 13 | 14 | public abstract void addToMap(MapView map); 15 | 16 | public abstract void removeFromMap(MapView map); 17 | 18 | public abstract Object getFeature(); 19 | } 20 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapFileTile.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import androidx.annotation.NonNull; 5 | import android.util.Log; 6 | 7 | import org.osmdroid.tileprovider.modules.ArchiveFileFactory; 8 | import org.osmdroid.tileprovider.modules.IArchiveFile; 9 | import org.osmdroid.tileprovider.modules.OfflineTileProvider; 10 | import org.osmdroid.tileprovider.tilesource.FileBasedTileSource; 11 | import org.osmdroid.tileprovider.tilesource.TileSourceFactory; 12 | import org.osmdroid.tileprovider.util.SimpleRegisterReceiver; 13 | import org.osmdroid.views.MapView; 14 | 15 | import java.io.File; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.Set; 19 | 20 | public class OsmMapFileTile extends OsmMapFeature { 21 | 22 | private final static String TAG = "OsmMapFileTile"; 23 | 24 | private float maximumZ = 100.f; 25 | private float minimumZ = 0; 26 | private String fileDirPath = "/offline_tiles/"; 27 | 28 | public OsmMapFileTile(Context context) { 29 | super(context); 30 | } 31 | 32 | @Override public void addToMap(MapView map) { 33 | setupMapProvider(map); 34 | map.setUseDataConnection(false); 35 | } 36 | 37 | @Override public void removeFromMap(MapView map) { 38 | map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE); 39 | } 40 | 41 | @Override public Object getFeature() { 42 | return null; 43 | } 44 | 45 | public void setMaximumZ(float maximumZ) { 46 | this.maximumZ = maximumZ; 47 | } 48 | 49 | public void setMinimumZ(float minimumZ) { 50 | this.minimumZ = minimumZ; 51 | } 52 | 53 | public void setFileDirPath(String filePath) { 54 | this.fileDirPath = filePath; 55 | } 56 | 57 | @NonNull 58 | private File[] findAllSupportedFilesInDirectory(File directory) { 59 | List candidates = new ArrayList<>(); 60 | File[] list = directory.listFiles(); 61 | for (int i = 0; i < list.length; i++) { 62 | if (list[i].isDirectory()) { 63 | continue; 64 | } 65 | String name = list[i].getName().toLowerCase(); 66 | if (!name.contains(".")) { 67 | continue; //skip files without an extension 68 | } 69 | name = name.substring(name.lastIndexOf(".") + 1); 70 | if (name.length() == 0) { 71 | continue; 72 | } 73 | if (ArchiveFileFactory.isFileExtensionRegistered(name)) { 74 | candidates.add(list[i]); 75 | } 76 | } 77 | return candidates.toArray(new File[0]); 78 | } 79 | 80 | private void setupMapProvider(@NonNull MapView map) { 81 | //first we'll look at the default location for tiles that we support 82 | Context context = map.getContext(); 83 | File f = new File(context.getFilesDir() + fileDirPath); 84 | if (f.exists() && f.isDirectory()) { 85 | 86 | File[] list = findAllSupportedFilesInDirectory(f); 87 | if (list.length > 0) { 88 | try { 89 | OfflineTileProvider tileProvider = 90 | new OfflineTileProvider(new SimpleRegisterReceiver(map.getContext()), list); 91 | map.setTileProvider(tileProvider); 92 | // setup tile source 93 | String source = ""; 94 | IArchiveFile[] archives = tileProvider.getArchives(); 95 | if (archives.length > 0) { 96 | //cheating a bit here, get the first archive file and ask for the tile sources 97 | // names it contains 98 | Set tileSources = archives[0].getTileSources(); 99 | //presumably, this would be a great place to tell your users which tiles sources 100 | // are available 101 | if (!tileSources.isEmpty()) { 102 | //ok good, we found at least one tile source, create a basic file based tile 103 | // source using that name 104 | //and set it. If we don't set it, osmdroid will attempt to use the default 105 | // source, which is "MAPNIK", 106 | //which probably won't match your offline tile source, unless it's MAPNIK 107 | source = tileSources.iterator().next(); 108 | map.setTileSource(FileBasedTileSource.getSource(source)); 109 | } else { 110 | map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE); 111 | } 112 | 113 | } else { 114 | map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE); 115 | } 116 | Log.d(TAG, "Using " + source); 117 | map.invalidate(); 118 | return; 119 | } catch (Exception ex) { 120 | ex.printStackTrace(); 121 | } 122 | } else { 123 | Log.d(TAG, f.getAbsolutePath() + " dir not found!"); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapFileTileManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import com.facebook.react.uimanager.ThemedReactContext; 4 | import com.facebook.react.uimanager.ViewGroupManager; 5 | import com.facebook.react.uimanager.annotations.ReactProp; 6 | 7 | public class OsmMapFileTileManager extends ViewGroupManager { 8 | 9 | public OsmMapFileTileManager() { 10 | super(); 11 | } 12 | 13 | @Override 14 | public String getName() { 15 | return "OsmMapFileTile"; 16 | } 17 | 18 | @Override 19 | public OsmMapFileTile createViewInstance(ThemedReactContext context) { 20 | return new OsmMapFileTile(context); 21 | } 22 | 23 | @ReactProp(name = "minimumZ", defaultFloat = 0.0f) 24 | public void setMinimumZ(OsmMapFileTile view, float minimumZ) { 25 | view.setMinimumZ(minimumZ); 26 | } 27 | 28 | @ReactProp(name = "maximumZ", defaultFloat = 100.0f) 29 | public void setMaximumZ(OsmMapFileTile view, float maximumZ) { 30 | view.setMaximumZ(maximumZ); 31 | } 32 | 33 | @ReactProp(name="fileDirPath") 34 | public void setFilePath(OsmMapFileTile view, String fileDirPath) { 35 | view.setFileDirPath(fileDirPath); 36 | } 37 | 38 | // todo create offline placeholder binding\ 39 | // //https://github.com/osmdroid/osmdroid/issues/330 40 | // //custom image placeholder for files that aren't available 41 | // mMapView.getTileProvider().setTileLoadFailureImage(getResources().getDrawable(R 42 | // .drawable.notfound)); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapMarkerManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.graphics.Color; 4 | import android.view.View; 5 | 6 | import com.osmdroid.utils.SizeReportingShadowNode; 7 | import com.facebook.react.bridge.ReadableArray; 8 | import com.facebook.react.bridge.ReadableMap; 9 | import com.facebook.react.common.MapBuilder; 10 | import com.facebook.react.uimanager.LayoutShadowNode; 11 | import com.facebook.react.uimanager.ThemedReactContext; 12 | import com.facebook.react.uimanager.ViewGroupManager; 13 | import com.facebook.react.uimanager.annotations.ReactProp; 14 | 15 | import org.osmdroid.views.overlay.Marker; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import javax.annotation.Nullable; 21 | 22 | public class OsmMapMarkerManager extends ViewGroupManager { 23 | 24 | private static final int SHOW_INFO_WINDOW = 1; 25 | private static final int HIDE_INFO_WINDOW = 2; 26 | 27 | public OsmMapMarkerManager() { 28 | } 29 | 30 | @Override 31 | public String getName() { 32 | return "OsmMapMarker"; 33 | } 34 | 35 | @Override 36 | public OsmMapMarker createViewInstance(ThemedReactContext context) { 37 | return new OsmMapMarker(context); 38 | } 39 | 40 | @Override 41 | public void onDropViewInstance(OsmMapMarker view) { 42 | view.cleanup(); 43 | super.onDropViewInstance(view); 44 | } 45 | 46 | @ReactProp(name = "coordinate") 47 | public void setCoordinate(OsmMapMarker view, ReadableMap map) { 48 | view.setCoordinate(map); 49 | } 50 | 51 | @ReactProp(name = "title") 52 | public void setTitle(OsmMapMarker view, String title) { 53 | view.setTitle(title); 54 | } 55 | 56 | @ReactProp(name = "identifier") 57 | public void setIdentifier(OsmMapMarker view, String identifier) { 58 | view.setIdentifier(identifier); 59 | } 60 | 61 | @ReactProp(name = "description") 62 | public void setDescription(OsmMapMarker view, String description) { 63 | view.setSnippet(description); 64 | } 65 | 66 | // NOTE(lmr): 67 | // android uses normalized coordinate systems for this, and is provided through the 68 | // `anchor` property and `calloutAnchor` instead. Perhaps some work could be done 69 | // to normalize iOS and android to use just one of the systems. 70 | // @ReactProp(name = "centerOffset") 71 | // public void setCenterOffset(AirMapMarker view, ReadableMap map) { 72 | // 73 | // } 74 | // 75 | // @ReactProp(name = "calloutOffset") 76 | // public void setCalloutOffset(AirMapMarker view, ReadableMap map) { 77 | // 78 | // } 79 | 80 | @ReactProp(name = "anchor") 81 | public void setAnchor(OsmMapMarker view, ReadableMap map) { 82 | // should default to (0.5, 1) (bottom middle) 83 | double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5; 84 | double y = map != null && map.hasKey("y") ? map.getDouble("y") : 1.0; 85 | view.setAnchor(x, y); 86 | } 87 | 88 | @ReactProp(name = "calloutAnchor") 89 | public void setCalloutAnchor(OsmMapMarker view, ReadableMap map) { 90 | // should default to (0.5, 0) (top middle) 91 | double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5; 92 | double y = map != null && map.hasKey("y") ? map.getDouble("y") : 0.0; 93 | view.setCalloutAnchor(x, y); 94 | } 95 | 96 | @ReactProp(name = "image") 97 | public void setImage(OsmMapMarker view, @Nullable String source) { 98 | view.setImage(source); 99 | } 100 | // public void setImage(AirMapMarker view, ReadableMap image) { 101 | // view.setImage(image); 102 | // } 103 | 104 | @ReactProp(name = "pinColor", defaultInt = Color.RED, customType = "Color") 105 | public void setPinColor(OsmMapMarker view, int pinColor) { 106 | float[] hsv = new float[3]; 107 | Color.colorToHSV(pinColor, hsv); 108 | // NOTE: android only supports a hue 109 | view.setMarkerHue(hsv[0]); 110 | } 111 | 112 | @ReactProp(name = "rotation", defaultFloat = 0.0f) 113 | public void setMarkerRotation(OsmMapMarker view, float rotation) { 114 | view.setRotation(rotation); 115 | } 116 | 117 | @ReactProp(name = "flat", defaultBoolean = false) 118 | public void setFlat(OsmMapMarker view, boolean flat) { 119 | view.setFlat(flat); 120 | } 121 | 122 | @ReactProp(name = "draggable", defaultBoolean = false) 123 | public void setDraggable(OsmMapMarker view, boolean draggable) { 124 | view.setDraggable(draggable); 125 | } 126 | 127 | // @Override 128 | // @ReactProp(name = "zIndex", defaultFloat = 0.0f) 129 | // public void setZIndex(AirMapMarker view, float zIndex) { 130 | // super.setZIndex(view, zIndex); 131 | // int integerZIndex = Math.round(zIndex); 132 | // view.setZIndex(integerZIndex); 133 | // } 134 | 135 | @Override 136 | @ReactProp(name = "opacity", defaultFloat = 1.0f) 137 | public void setOpacity(OsmMapMarker view, float opacity) { 138 | super.setOpacity(view, opacity); 139 | view.setOpacity(opacity); 140 | } 141 | 142 | @Override 143 | public void addView(OsmMapMarker parent, View child, int index) { 144 | // if an component is a child, then it is a callout view, NOT part of the 145 | // marker. 146 | if (child instanceof OsmMapCallout) { 147 | parent.setCalloutView((OsmMapCallout) child); 148 | } else { 149 | super.addView(parent, child, index); 150 | parent.update(); 151 | } 152 | } 153 | 154 | @Override 155 | public void removeViewAt(OsmMapMarker parent, int index) { 156 | super.removeViewAt(parent, index); 157 | parent.update(); 158 | } 159 | 160 | @Override 161 | @Nullable 162 | public Map getCommandsMap() { 163 | return MapBuilder.of( 164 | "showCallout", SHOW_INFO_WINDOW, 165 | "hideCallout", HIDE_INFO_WINDOW 166 | ); 167 | } 168 | 169 | @Override 170 | public void receiveCommand(OsmMapMarker view, int commandId, @Nullable ReadableArray args) { 171 | switch (commandId) { 172 | case SHOW_INFO_WINDOW: 173 | ((Marker) view.getFeature()).showInfoWindow(); 174 | break; 175 | 176 | case HIDE_INFO_WINDOW: 177 | ((Marker) view.getFeature()).closeInfoWindow(); 178 | break; 179 | } 180 | } 181 | 182 | @Override 183 | @Nullable 184 | public Map getExportedCustomDirectEventTypeConstants() { 185 | Map> map = MapBuilder.of( 186 | "onPress", MapBuilder.of("registrationName", "onPress"), 187 | "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress"), 188 | "onDragStart", MapBuilder.of("registrationName", "onDragStart"), 189 | "onDrag", MapBuilder.of("registrationName", "onDrag"), 190 | "onDragEnd", MapBuilder.of("registrationName", "onDragEnd") 191 | ); 192 | 193 | map.putAll(MapBuilder.of( 194 | "onDragStart", MapBuilder.of("registrationName", "onDragStart"), 195 | "onDrag", MapBuilder.of("registrationName", "onDrag"), 196 | "onDragEnd", MapBuilder.of("registrationName", "onDragEnd") 197 | )); 198 | 199 | return map; 200 | } 201 | 202 | @Override 203 | public LayoutShadowNode createShadowNodeInstance() { 204 | // we use a custom shadow node that emits the width/height of the view 205 | // after layout with the updateExtraData method. Without this, we can't generate 206 | // a bitmap of the appropriate width/height of the rendered view. 207 | return new SizeReportingShadowNode(); 208 | } 209 | 210 | @Override 211 | public void updateExtraData(OsmMapMarker view, Object extraData) { 212 | // This method is called from the shadow node with the width/height of the rendered 213 | // marker view. 214 | HashMap data = (HashMap) extraData; 215 | float width = data.get("width"); 216 | float height = data.get("height"); 217 | view.update((int) width, (int) height); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapPolygon.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | 5 | import com.facebook.react.bridge.ReadableArray; 6 | import com.facebook.react.bridge.ReadableMap; 7 | 8 | import org.osmdroid.util.GeoPoint; 9 | import org.osmdroid.views.MapView; 10 | import org.osmdroid.views.overlay.Polygon; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class OsmMapPolygon extends OsmMapFeature { 16 | 17 | private Polygon polygon; 18 | 19 | private List coordinates; 20 | private int strokeColor; 21 | private int fillColor; 22 | private float strokeWidth; 23 | private MapView mapView; 24 | 25 | public OsmMapPolygon(Context context) { 26 | super(context); 27 | } 28 | 29 | public void setCoordinates(ReadableArray coordinates) { 30 | // it's kind of a bummer that we can't run map() or anything on the ReadableArray 31 | this.coordinates = new ArrayList<>(coordinates.size()+1); 32 | for (int i = 0; i < coordinates.size(); i++) { 33 | ReadableMap coordinate = coordinates.getMap(i); 34 | this.coordinates.add(i, 35 | new GeoPoint(coordinate.getDouble("latitude"), coordinate.getDouble("longitude"))); 36 | } 37 | this.coordinates.add(this.coordinates.get(0)); 38 | if (polygon != null) { 39 | polygon.setPoints(this.coordinates); 40 | mapView.invalidate(); 41 | } 42 | } 43 | 44 | public void setFillColor(int color) { 45 | this.fillColor = color; 46 | if (polygon != null) { 47 | polygon.getFillPaint().setColor(color); 48 | mapView.invalidate(); 49 | } 50 | } 51 | 52 | public void setStrokeColor(int color) { 53 | this.strokeColor = color; 54 | if (polygon != null) { 55 | polygon.getOutlinePaint().setColor(color); 56 | mapView.invalidate(); 57 | } 58 | } 59 | 60 | public void setStrokeWidth(float width) { 61 | this.strokeWidth = width; 62 | if (polygon != null) { 63 | polygon.getOutlinePaint().setStrokeWidth(width); 64 | mapView.invalidate(); 65 | } 66 | } 67 | 68 | 69 | @Override 70 | public Object getFeature() { 71 | return polygon; 72 | } 73 | 74 | @Override 75 | public void addToMap(MapView map) { 76 | polygon = new Polygon(); 77 | mapView = map; 78 | polygon.setPoints(coordinates); 79 | polygon.getFillPaint().setColor(fillColor); 80 | polygon.getOutlinePaint().setColor(strokeColor); 81 | polygon.getOutlinePaint().setStrokeWidth(strokeWidth); 82 | map.getOverlays().add(polygon); 83 | mapView.invalidate(); 84 | } 85 | 86 | @Override 87 | public void removeFromMap(MapView map) { 88 | map.getOverlays().remove(polygon); 89 | polygon = null; 90 | mapView = null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapPolygonManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.util.DisplayMetrics; 7 | import android.view.WindowManager; 8 | 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.bridge.ReadableArray; 11 | import com.facebook.react.common.MapBuilder; 12 | import com.facebook.react.uimanager.ThemedReactContext; 13 | import com.facebook.react.uimanager.ViewGroupManager; 14 | import com.facebook.react.uimanager.annotations.ReactProp; 15 | 16 | import java.util.Map; 17 | 18 | import javax.annotation.Nullable; 19 | 20 | public class OsmMapPolygonManager extends ViewGroupManager { 21 | private final DisplayMetrics metrics; 22 | 23 | public OsmMapPolygonManager(ReactApplicationContext reactContext) { 24 | super(); 25 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 26 | metrics = new DisplayMetrics(); 27 | ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE)) 28 | .getDefaultDisplay() 29 | .getRealMetrics(metrics); 30 | } else { 31 | metrics = reactContext.getResources().getDisplayMetrics(); 32 | } 33 | } 34 | 35 | @Override 36 | public String getName() { 37 | return "OsmMapPolygon"; 38 | } 39 | 40 | @Override 41 | public OsmMapPolygon createViewInstance(ThemedReactContext context) { 42 | return new OsmMapPolygon(context); 43 | } 44 | 45 | @ReactProp(name = "coordinates") 46 | public void setCoordinate(OsmMapPolygon view, ReadableArray coordinates) { 47 | view.setCoordinates(coordinates); 48 | } 49 | 50 | @ReactProp(name = "strokeWidth", defaultFloat = 1f) 51 | public void setStrokeWidth(OsmMapPolygon view, float widthInPoints) { 52 | float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS 53 | view.setStrokeWidth(widthInScreenPx); 54 | } 55 | 56 | @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color") 57 | public void setFillColor(OsmMapPolygon view, int color) { 58 | view.setFillColor(color); 59 | } 60 | 61 | @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color") 62 | public void setStrokeColor(OsmMapPolygon view, int color) { 63 | view.setStrokeColor(color); 64 | } 65 | 66 | 67 | @Override 68 | @Nullable 69 | public Map getExportedCustomDirectEventTypeConstants() { 70 | return MapBuilder.of( 71 | "onPress", MapBuilder.of("registrationName", "onPress") 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapPolyline.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | 5 | import com.facebook.react.bridge.ReadableArray; 6 | import com.facebook.react.bridge.ReadableMap; 7 | 8 | import org.osmdroid.util.GeoPoint; 9 | import org.osmdroid.views.MapView; 10 | import org.osmdroid.views.overlay.Polyline; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class OsmMapPolyline extends OsmMapFeature { 16 | 17 | private Polyline polyline; 18 | 19 | private List coordinates; 20 | private int color; 21 | private float width; 22 | private boolean geodesic; 23 | // private float zIndex; 24 | private MapView mapView; 25 | 26 | public OsmMapPolyline(Context context) { 27 | super(context); 28 | } 29 | 30 | public void setCoordinates(ReadableArray coordinates) { 31 | this.coordinates = new ArrayList<>(coordinates.size()); 32 | for (int i = 0; i < coordinates.size(); i++) { 33 | ReadableMap coordinate = coordinates.getMap(i); 34 | this.coordinates.add(i, 35 | new GeoPoint(coordinate.getDouble("latitude"), coordinate.getDouble("longitude"))); 36 | } 37 | if (polyline != null) { 38 | polyline.setPoints(this.coordinates); 39 | mapView.invalidate(); 40 | } 41 | } 42 | 43 | public void setColor(int color) { 44 | this.color = color; 45 | if (polyline != null) { 46 | polyline.getOutlinePaint().setColor(color); 47 | mapView.invalidate(); 48 | } 49 | } 50 | 51 | public void setWidth(float width) { 52 | this.width = width; 53 | if (polyline != null) { 54 | polyline.getOutlinePaint().setStrokeWidth(width); 55 | mapView.invalidate(); 56 | } 57 | } 58 | 59 | public void setGeodesic(boolean geodesic) { 60 | this.geodesic = geodesic; 61 | if (polyline != null) { 62 | polyline.setGeodesic(geodesic); 63 | mapView.invalidate(); 64 | } 65 | } 66 | 67 | @Override 68 | public Object getFeature() { 69 | return polyline; 70 | } 71 | 72 | @Override 73 | public void addToMap(MapView map) { 74 | polyline = new Polyline(); 75 | mapView = map; 76 | polyline.setPoints(coordinates); 77 | polyline.getOutlinePaint().setColor(color); 78 | polyline.getOutlinePaint().setStrokeWidth(width); 79 | polyline.setGeodesic(geodesic); 80 | mapView.getOverlayManager().add(polyline); 81 | mapView.invalidate(); 82 | } 83 | 84 | @Override 85 | public void removeFromMap(MapView map) { 86 | map.getOverlays().remove(polyline); 87 | polyline = null; 88 | mapView = null; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapPolylineManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.util.DisplayMetrics; 7 | import android.view.WindowManager; 8 | 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.bridge.ReadableArray; 11 | import com.facebook.react.common.MapBuilder; 12 | import com.facebook.react.uimanager.ThemedReactContext; 13 | import com.facebook.react.uimanager.ViewGroupManager; 14 | import com.facebook.react.uimanager.annotations.ReactProp; 15 | 16 | import java.util.Map; 17 | 18 | import javax.annotation.Nullable; 19 | 20 | public class OsmMapPolylineManager extends ViewGroupManager { 21 | private final DisplayMetrics metrics; 22 | 23 | public OsmMapPolylineManager(ReactApplicationContext reactContext) { 24 | super(); 25 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 26 | metrics = new DisplayMetrics(); 27 | ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE)) 28 | .getDefaultDisplay() 29 | .getRealMetrics(metrics); 30 | } else { 31 | metrics = reactContext.getResources().getDisplayMetrics(); 32 | } 33 | } 34 | 35 | @Override 36 | public String getName() { 37 | return "OsmMapPolyline"; 38 | } 39 | 40 | @Override 41 | public OsmMapPolyline createViewInstance(ThemedReactContext context) { 42 | return new OsmMapPolyline(context); 43 | } 44 | 45 | @ReactProp(name = "coordinates") 46 | public void setCoordinate(OsmMapPolyline view, ReadableArray coordinates) { 47 | view.setCoordinates(coordinates); 48 | } 49 | 50 | @ReactProp(name = "strokeWidth", defaultFloat = 1f) 51 | public void setStrokeWidth(OsmMapPolyline view, float widthInPoints) { 52 | float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS 53 | view.setWidth(widthInScreenPx); 54 | } 55 | 56 | @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color") 57 | public void setStrokeColor(OsmMapPolyline view, int color) { 58 | view.setColor(color); 59 | } 60 | 61 | @ReactProp(name = "geodesic", defaultBoolean = false) 62 | public void setGeodesic(OsmMapPolyline view, boolean geodesic) { 63 | view.setGeodesic(geodesic); 64 | } 65 | 66 | 67 | @Override 68 | @Nullable 69 | public Map getExportedCustomDirectEventTypeConstants() { 70 | return MapBuilder.of( 71 | "onPress", MapBuilder.of("registrationName", "onPress") 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapUrlTile.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | 7 | import org.osmdroid.tileprovider.tilesource.ITileSource; 8 | import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase; 9 | import org.osmdroid.tileprovider.tilesource.TileSourceFactory; 10 | import org.osmdroid.util.MapTileIndex; 11 | import org.osmdroid.views.MapView; 12 | 13 | 14 | public class OsmMapUrlTile extends OsmMapFeature { 15 | 16 | 17 | private String urlTemplate; 18 | private float maximumZ = 100.f; 19 | private float minimumZ = 0; 20 | 21 | public class OsmMapTileSource extends OnlineTileSourceBase { 22 | 23 | public OsmMapTileSource(final String aName, final int aZoomMinLevel, 24 | final int aZoomMaxLevel, final int aTileSizePixels, 25 | final String urlTemplate) { 26 | super(aName, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels, 27 | null, new String[]{urlTemplate}, null); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return name(); 33 | } 34 | 35 | @Override 36 | public String getTileURLString(final long pMapTileIndex) { 37 | String url = getBaseUrl() 38 | .replace("{x}", Integer.toString(MapTileIndex.getX(pMapTileIndex))) 39 | .replace("{y}", Integer.toString(MapTileIndex.getY(pMapTileIndex))) 40 | .replace("{z}", Integer.toString(MapTileIndex.getZoom(pMapTileIndex))); 41 | 42 | Log.e("OsmMapTileSource", url); 43 | return url; 44 | } 45 | 46 | @Override 47 | public String getTileRelativeFilenameString(long pMapTileIndex) { 48 | return pathBase() 49 | .replace("{x}", Integer.toString(MapTileIndex.getX(pMapTileIndex))) 50 | .replace("{y}", Integer.toString(MapTileIndex.getY(pMapTileIndex))) 51 | .replace("{z}", Integer.toString(MapTileIndex.getZoom(pMapTileIndex))); 52 | } 53 | } 54 | 55 | public OsmMapUrlTile(Context context) { 56 | super(context); 57 | } 58 | 59 | public void setUrlTemplate(String urlTemplate) { 60 | this.urlTemplate = urlTemplate; 61 | } 62 | 63 | public void setMaximumZ(float maximumZ) { 64 | this.maximumZ = maximumZ; 65 | } 66 | 67 | public void setMinimumZ(float minimumZ) { 68 | this.minimumZ = minimumZ; 69 | } 70 | 71 | @Override 72 | public Object getFeature() { 73 | return this; 74 | } 75 | 76 | @Override 77 | public void addToMap(MapView map) { 78 | final ITileSource tileSource = new OsmMapTileSource("OsmMapTileSource", (int) minimumZ, (int) maximumZ, 256, urlTemplate); 79 | map.setTileSource(tileSource); 80 | } 81 | 82 | @Override 83 | public void removeFromMap(MapView map) { 84 | map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmMapUrlTileManager.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.util.DisplayMetrics; 6 | import android.view.WindowManager; 7 | 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.uimanager.ThemedReactContext; 10 | import com.facebook.react.uimanager.ViewGroupManager; 11 | import com.facebook.react.uimanager.annotations.ReactProp; 12 | 13 | public class OsmMapUrlTileManager extends ViewGroupManager { 14 | 15 | public OsmMapUrlTileManager() { 16 | super(); 17 | } 18 | 19 | @Override 20 | public String getName() { 21 | return "OsmMapUrlTile"; 22 | } 23 | 24 | @Override 25 | public OsmMapUrlTile createViewInstance(ThemedReactContext context) { 26 | return new OsmMapUrlTile(context); 27 | } 28 | 29 | @ReactProp(name = "urlTemplate") 30 | public void setUrlTemplate(OsmMapUrlTile view, String urlTemplate) { 31 | view.setUrlTemplate(urlTemplate); 32 | } 33 | 34 | @ReactProp(name = "minimumZ", defaultFloat = 0.0f) 35 | public void setMinimumZ(OsmMapUrlTile view, float minimumZ) { 36 | view.setMinimumZ(minimumZ); 37 | } 38 | 39 | @ReactProp(name = "maximumZ", defaultFloat = 100.0f) 40 | public void setMaximumZ(OsmMapUrlTile view, float maximumZ) { 41 | view.setMaximumZ(maximumZ); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmRegionChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import com.facebook.react.bridge.WritableMap; 4 | import com.facebook.react.bridge.WritableNativeMap; 5 | import com.facebook.react.uimanager.events.Event; 6 | import com.facebook.react.uimanager.events.RCTEventEmitter; 7 | import org.osmdroid.api.IGeoPoint; 8 | import org.osmdroid.util.BoundingBox; 9 | 10 | public class OsmRegionChangeEvent extends Event { 11 | private final BoundingBox bounds; 12 | private final IGeoPoint center; 13 | private final boolean continuous; 14 | 15 | public OsmRegionChangeEvent(int id, BoundingBox bounds, IGeoPoint center, boolean continuous) { 16 | super(id); 17 | this.bounds = bounds; 18 | this.center = center; 19 | this.continuous = continuous; 20 | } 21 | 22 | @Override 23 | public String getEventName() { 24 | return "topChange"; 25 | } 26 | 27 | @Override 28 | public boolean canCoalesce() { 29 | return false; 30 | } 31 | 32 | @Override 33 | public void dispatch(RCTEventEmitter rctEventEmitter) { 34 | 35 | WritableMap event = new WritableNativeMap(); 36 | event.putBoolean("continuous", continuous); 37 | 38 | WritableMap region = new WritableNativeMap(); 39 | region.putDouble("latitude", center.getLatitude()); 40 | region.putDouble("longitude", center.getLongitude()); 41 | region.putDouble("latitudeDelta", bounds.getLatitudeSpan()); 42 | region.putDouble("longitudeDelta", bounds.getLongitudeSpanWithDateLine()); 43 | event.putMap("region", region); 44 | 45 | rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/OsmdroidPackage.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.NativeModule; 5 | import com.facebook.react.bridge.ReactApplicationContext; 6 | import com.facebook.react.uimanager.ViewManager; 7 | 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | public class OsmdroidPackage implements ReactPackage { 12 | @Override 13 | public List createNativeModules(ReactApplicationContext reactContext) { 14 | return Arrays.asList(new OsmMapModule(reactContext)); 15 | } 16 | 17 | @Override 18 | public List createViewManagers(ReactApplicationContext reactContext) { 19 | OsmMapCalloutManager osmCalloutManager = new OsmMapCalloutManager(); 20 | OsmMapMarkerManager osmMarkerManager = new OsmMapMarkerManager(); 21 | OsmMapPolylineManager osmPolylineManager = new OsmMapPolylineManager(reactContext); 22 | OsmMapPolygonManager osmPolygonManager = new OsmMapPolygonManager(reactContext); 23 | OsmMapCircleManager osmMapCircleManager = new OsmMapCircleManager(reactContext); 24 | OsmMapManager osmMapManager = new OsmMapManager(reactContext); 25 | OsmMapUrlTileManager osmUrlTileManager = new OsmMapUrlTileManager(); 26 | OsmMapFileTileManager osmMapFileTileManager = new OsmMapFileTileManager(); 27 | return Arrays.asList( 28 | osmCalloutManager, 29 | osmMarkerManager, 30 | osmPolylineManager, 31 | osmPolygonManager, 32 | osmMapCircleManager, 33 | osmMapManager, 34 | osmUrlTileManager, 35 | osmMapFileTileManager); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/overlays/InterceptDoubleTapOverlay.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.overlays; 2 | 3 | import android.graphics.Canvas; 4 | import android.view.MotionEvent; 5 | 6 | import org.osmdroid.views.MapView; 7 | import org.osmdroid.views.overlay.Overlay; 8 | 9 | public class InterceptDoubleTapOverlay extends Overlay { 10 | 11 | public InterceptDoubleTapOverlay() { 12 | } 13 | 14 | @Override public void draw(Canvas canvas, MapView mapView, boolean b) { 15 | } 16 | 17 | @Override 18 | public boolean onDoubleTap(MotionEvent e, MapView mapView) { 19 | return isEnabled(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/overlays/InterceptScrollOverlay.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.overlays; 2 | 3 | import android.graphics.Canvas; 4 | import android.view.MotionEvent; 5 | 6 | import org.osmdroid.views.MapView; 7 | import org.osmdroid.views.overlay.Overlay; 8 | 9 | public class InterceptScrollOverlay extends Overlay { 10 | 11 | public InterceptScrollOverlay() { 12 | } 13 | 14 | @Override public void draw(Canvas canvas, MapView mapView, boolean b) { 15 | } 16 | 17 | @Override public boolean onScroll(MotionEvent pEvent1, MotionEvent pEvent2, float pDistanceX, 18 | float pDistanceY, MapView pMapView) { 19 | return isEnabled(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.utils; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | import android.os.AsyncTask; 6 | 7 | import com.facebook.common.logging.FLog; 8 | import com.facebook.react.common.ReactConstants; 9 | 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileOutputStream; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.net.URL; 16 | import java.nio.channels.Channels; 17 | import java.nio.channels.ReadableByteChannel; 18 | 19 | public class FileUtil extends AsyncTask { 20 | 21 | private final String NAME = "FileUtil"; 22 | private final String TEMP_FILE_SUFFIX = "temp"; 23 | 24 | private Exception exception; 25 | private Context context; 26 | 27 | public FileUtil(Context context) { 28 | super(); 29 | 30 | this.context = context; 31 | } 32 | 33 | protected InputStream doInBackground(String... urls) { 34 | try { 35 | Uri fileContentUri = Uri.parse(urls[0]); 36 | 37 | if (fileContentUri.getScheme().startsWith("http")) { 38 | return getDownloadFileInputStream(context, fileContentUri); 39 | } 40 | return context.getContentResolver().openInputStream(fileContentUri); 41 | } catch (Exception e) { 42 | this.exception = e; 43 | FLog.e( 44 | ReactConstants.TAG, 45 | "Could not retrieve file for contentUri " + urls[0], 46 | e); 47 | return null; 48 | } 49 | } 50 | 51 | private InputStream getDownloadFileInputStream(Context context, Uri uri) 52 | throws IOException { 53 | final File outputDir = context.getApplicationContext().getCacheDir(); 54 | final File file = File.createTempFile(NAME, TEMP_FILE_SUFFIX, outputDir); 55 | file.deleteOnExit(); 56 | 57 | final URL url = new URL(uri.toString()); 58 | final InputStream is = url.openStream(); 59 | try { 60 | final ReadableByteChannel channel = Channels.newChannel(is); 61 | try { 62 | final FileOutputStream stream = new FileOutputStream(file); 63 | try { 64 | stream.getChannel().transferFrom(channel, 0, Long.MAX_VALUE); 65 | return new FileInputStream(file); 66 | } finally { 67 | stream.close(); 68 | } 69 | } finally { 70 | channel.close(); 71 | } 72 | } finally { 73 | is.close(); 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/utils/ImageReadable.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.utils; 2 | 3 | 4 | import android.graphics.Bitmap; 5 | 6 | public interface ImageReadable { 7 | 8 | public void setIconBitmap(Bitmap bitmap); 9 | 10 | public void update(); 11 | } 12 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/utils/ImageReader.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.drawable.Animatable; 7 | import android.net.Uri; 8 | 9 | import com.facebook.common.references.CloseableReference; 10 | import com.facebook.datasource.DataSource; 11 | import com.facebook.drawee.backends.pipeline.Fresco; 12 | import com.facebook.drawee.controller.BaseControllerListener; 13 | import com.facebook.drawee.controller.ControllerListener; 14 | import com.facebook.drawee.drawable.ScalingUtils; 15 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 16 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 17 | import com.facebook.drawee.interfaces.DraweeController; 18 | import com.facebook.drawee.view.DraweeHolder; 19 | import com.facebook.imagepipeline.core.ImagePipeline; 20 | import com.facebook.imagepipeline.image.CloseableImage; 21 | import com.facebook.imagepipeline.image.CloseableStaticBitmap; 22 | import com.facebook.imagepipeline.image.ImageInfo; 23 | import com.facebook.imagepipeline.request.ImageRequest; 24 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 25 | 26 | import javax.annotation.Nullable; 27 | 28 | public class ImageReader { 29 | 30 | private final ImageReadable imp; 31 | private final Context context; 32 | private final Resources resources; 33 | 34 | private final DraweeHolder logoHolder; 35 | private DataSource> dataSource; 36 | 37 | private final ControllerListener mLogoControllerListener = 38 | new BaseControllerListener() { 39 | @Override 40 | public void onFinalImageSet( 41 | String id, 42 | @Nullable final ImageInfo imageInfo, 43 | @Nullable Animatable animatable) { 44 | CloseableReference imageReference = null; 45 | try { 46 | imageReference = dataSource.getResult(); 47 | if (imageReference != null) { 48 | CloseableImage image = imageReference.get(); 49 | if (image != null && image instanceof CloseableStaticBitmap) { 50 | CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; 51 | Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap(); 52 | if (bitmap != null) { 53 | bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); 54 | imp.setIconBitmap(bitmap); 55 | } 56 | } 57 | } 58 | } finally { 59 | dataSource.close(); 60 | if (imageReference != null) { 61 | CloseableReference.closeSafely(imageReference); 62 | } 63 | } 64 | imp.update(); 65 | } 66 | }; 67 | 68 | public ImageReader(Context context, Resources resources, ImageReadable imp) { 69 | this.context = context; 70 | this.resources = resources; 71 | this.imp = imp; 72 | logoHolder = DraweeHolder.create(createDraweeHeirarchy(resources), context); 73 | logoHolder.onAttach(); 74 | } 75 | 76 | private GenericDraweeHierarchy createDraweeHeirarchy(Resources resources){ 77 | return new GenericDraweeHierarchyBuilder(resources) 78 | .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER) 79 | .setFadeDuration(0) 80 | .build(); 81 | } 82 | 83 | public void setImage(String uri) { 84 | if (uri == null) { 85 | imp.update(); 86 | } else if (uri.startsWith("http://") || uri.startsWith("https://") || 87 | uri.startsWith("file://") || uri.startsWith("asset://")) { 88 | ImageRequest imageRequest = ImageRequestBuilder 89 | .newBuilderWithSource(Uri.parse(uri)) 90 | .build(); 91 | ImagePipeline imagePipeline = Fresco.getImagePipeline(); 92 | dataSource = imagePipeline.fetchDecodedImage(imageRequest, this); 93 | 94 | DraweeController controller = Fresco.newDraweeControllerBuilder() 95 | .setImageRequest(imageRequest) 96 | .setControllerListener(mLogoControllerListener) 97 | .setOldController(logoHolder.getController()) 98 | .build(); 99 | logoHolder.setController(controller); 100 | } else { 101 | imp.update(); 102 | } 103 | 104 | 105 | } 106 | 107 | private int getDrawableResourceByName(String name) { 108 | return this.resources.getIdentifier( 109 | name, 110 | "drawable", 111 | this.context.getPackageName()); 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/utils/ImageUtil.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.utils; 2 | 3 | 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.util.Base64; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | 10 | public class ImageUtil { 11 | public static Bitmap convert(String base64Str) throws IllegalArgumentException { 12 | byte[] decodedBytes = Base64.decode( 13 | base64Str.substring(base64Str.indexOf(",") + 1), 14 | Base64.DEFAULT 15 | ); 16 | 17 | return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length); 18 | } 19 | 20 | public static String convert(Bitmap bitmap) { 21 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 22 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); 23 | 24 | return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/utils/LatLngBoundsUtils.java: -------------------------------------------------------------------------------- 1 | package com.osmdroid.utils; 2 | 3 | import org.osmdroid.util.BoundingBox; 4 | import org.osmdroid.util.GeoPoint; 5 | 6 | public class LatLngBoundsUtils { 7 | public static boolean BoundsAreDifferent(BoundingBox a, BoundingBox b) { 8 | GeoPoint centerA = a.getCenterWithDateLine(); 9 | double latA = centerA.getLatitude(); 10 | double lngA = centerA.getLongitude(); 11 | double latDeltaA = a.getLatitudeSpan(); 12 | double lngDeltaA = a.getLongitudeSpanWithDateLine(); 13 | 14 | GeoPoint centerB = b.getCenterWithDateLine(); 15 | double latB = centerB.getLatitude(); 16 | double lngB = centerB.getLongitude(); 17 | double latDeltaB = b.getLatitudeSpan(); 18 | double lngDeltaB = b.getLongitudeSpanWithDateLine(); 19 | 20 | double latEps = LatitudeEpsilon(a, b); 21 | double lngEps = LongitudeEpsilon(a, b); 22 | 23 | return 24 | different(latA, latB, latEps) || 25 | different(lngA, lngB, lngEps) || 26 | different(latDeltaA, latDeltaB, latEps) || 27 | different(lngDeltaA, lngDeltaB, lngEps); 28 | } 29 | 30 | private static boolean different(double a, double b, double epsilon) { 31 | return Math.abs(a - b) > epsilon; 32 | } 33 | 34 | private static double LatitudeEpsilon(BoundingBox a, BoundingBox b) { 35 | double sizeA = a.getLatitudeSpan(); // something mod 180? 36 | double sizeB = b.getLatitudeSpan(); // something mod 180? 37 | double size = Math.min(Math.abs(sizeA), Math.abs(sizeB)); 38 | return size / 2560; 39 | } 40 | 41 | private static double LongitudeEpsilon(BoundingBox a, BoundingBox b) { 42 | double sizeA = a.getLongitudeSpanWithDateLine(); 43 | double sizeB = b.getLongitudeSpanWithDateLine(); 44 | double size = Math.min(Math.abs(sizeA), Math.abs(sizeB)); 45 | return size / 2560; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /android/src/main/java/com/osmdroid/utils/SizeReportingShadowNode.java: -------------------------------------------------------------------------------- 1 | 2 | package com.osmdroid.utils; 3 | 4 | import com.facebook.react.uimanager.LayoutShadowNode; 5 | import com.facebook.react.uimanager.UIViewOperationQueue; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | // Custom LayoutShadowNode implementation used in conjunction with the AirMapManager 11 | // which sends the width/height of the view after layout occurs. 12 | public class SizeReportingShadowNode extends LayoutShadowNode { 13 | 14 | @Override 15 | public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { 16 | super.onCollectExtraUpdates(uiViewOperationQueue); 17 | 18 | Map data = new HashMap<>(); 19 | data.put("width", getLayoutWidth()); 20 | data.put("height", getLayoutHeight()); 21 | 22 | uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), data); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/callout.md: -------------------------------------------------------------------------------- 1 | # `` Component API 2 | 3 | ## Props 4 | 5 | | Prop | Type | Default | Note | 6 | |---|---|---|---| 7 | | `tooltip` | `Boolean` | `false` | If `false`, a default "tooltip" bubble window will be drawn around this callouts children. If `true`, the child views can fully customize their appearance, including any "bubble" like styles. 8 | 9 | 10 | ## Events 11 | 12 | | Event Name | Returns | Notes 13 | |---|---|---| 14 | | `onPress` | | Callback that is called when the user presses on the callout 15 | 16 | 17 | 18 | --- 19 | 20 | -------------------------------------------------------------------------------- /docs/circle.md: -------------------------------------------------------------------------------- 1 | # `` Component API 2 | 3 | ## Props 4 | 5 | | Prop | Type | Default | Note | 6 | |---|---|---|---| 7 | | `center` | `LatLng` | (Required) | The coordinate of the center of the circle 8 | | `radius` | `Number` | (Required) | The radius of the circle to be drawn (in meters) 9 | | `strokeWidth` | `Number` | `1` | The stroke width to use for the path. 10 | | `strokeColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The stroke color to use for the path. 11 | | `fillColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The fill color to use for the path. 12 | 13 | 14 | ## Types 15 | 16 | ``` 17 | type LatLng { 18 | latitude: Number, 19 | longitude: Number, 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/geojson.md: -------------------------------------------------------------------------------- 1 | # `` Component API 2 | 3 | ## Props 4 | 5 | | Prop | Type | Default | Note | 6 | | --------- | ---- | ------------------------------------------------------ | ---- | 7 | | `geojson` | `GeoJSON` | | [Geojson](https://geojson.org/) description of object. | 8 | | `strokeColor` | `String` | `stroke` property in GeoJson if present else `#000` | The stroke color to use for polygons and polylines. | 9 | | `fillColor` | `String` | `fill` property in GeoJson | The fill color to use for polygons. | 10 | | `strokeWidth` | `Number` | `stroke-width` property in Geojson if present else `1` | The stroke width to use for polygons and polylines. | 11 | | `color` | `String` | `marker-color` property in GeoJson | The color to use for points. | 12 | | `lineDashPhase` | `Number` | | (iOS only) The offset (in points) at which to start drawing the dash pattern. Use this property to start drawing a dashed line partway through a segment or gap. For example, a phase value of 6 for the patter 5-2-3-2 would cause drawing to begin in the middle of the first gap. | 13 | | `lineDashPattern` | `Array` | | An array of numbers specifying the dash pattern to use for the path. The array contains one or more numbers that indicate the lengths (measured in points) of the line segments and gaps in the pattern. The values in the array alternate, starting with the first line segment length, followed by the first gap length, followed by the second line segment length, and so on. | 14 | | `lineCap` | `'butt' | 'round' | 'square'` | | The line cap style to apply to the open ends of the path. Possible values are `butt`, `round` or `square`. Note: lineCap is not yet supported for GoogleMaps provider on iOS. | 15 | | `lineJoin` | `'miter'| 'round' | 'bevel'` | | The line join style to apply to corners of the path. Possible values are `miter`, `round` or `bevel`. | 16 | | `miterLimit` | `Number` | | The limiting value that helps avoid spikes at junctions between connected line segments. The miter limit helps you avoid spikes in paths that use the `miter` `lineJoin` style. If the ratio of the miter length—that is, the diagonal length of the miter join—to the line thickness exceeds the miter limit, the joint is converted to a bevel join. The default miter limit is 10, which results in the conversion of miters whose angle at the joint is less than 11 degrees. | 17 | | `zIndex` | `Number` | | Layer level of the z-index value | 18 | | `onPress` | `Function` | | returns the selected overlay value with the onPress functionality | 19 | | `markerComponent` | `React Node` | | Component to render in place of the default marker when the overlay type is a `point` 20 | | `title` | `string` | | The title of the marker. This is only used if the component has no children that are a `` 21 | | `tracksViewChanges` | `Boolean` | true | Sets whether this marker should track view changes. It's recommended to turn it off whenever it's possible to improve custom marker performance. This is the default value for all point markers in your geojson data. It can be overriden on a per point basis by adding a `trackViewChanges` property to the `properties` object on the point. 22 | 23 | ## Example 24 | 25 | ``` 26 | import React from 'react'; 27 | import MapView, {Geojson} from 'react-native-maps'; 28 | 29 | const myPlace = { 30 | type: 'FeatureCollection', 31 | features: [ 32 | { 33 | type: 'Feature', 34 | properties: {}, 35 | geometry: { 36 | type: 'Point', 37 | coordinates: [64.165329, 48.844287], 38 | } 39 | } 40 | ] 41 | }; 42 | 43 | const Map = props => ( 44 | 45 | 51 | 52 | ); 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/marker.md: -------------------------------------------------------------------------------- 1 | # `` Component API 2 | 3 | ## Props 4 | 5 | | Prop | Type | Default | Note | 6 | |---|---|---|---| 7 | | `title` | `String` | | The title of the marker. This is only used if the component has no children that are a ``, in which case the default callout behavior will be used, which will show both the `title` and the `description`, if provided. 8 | | `description` | `String` | | The description of the marker. This is only used if the component has no children that are a ``, in which case the default callout behavior will be used, which will show both the `title` and the `description`, if provided. 9 | | `image` | `ImageSource`* | | A custom image to be used as the marker's icon. Only local image resources are allowed to be used. 10 | | `icon` | `ImageSource`* | | Marker icon to render. Only local image resources are allowed to be used. 11 | | `pinColor` | `Color` | | If no custom marker view or custom image is provided, the platform default pin will be used, which can be customized by this color. Ignored if a custom marker is being used.

For Android, the set of available colors is limited. Unsupported colors will fall back to red. 12 | | `coordinate` | `LatLng` | | The coordinate for the marker. 13 | | `calloutOffset` | `Point` | (0, 0) | The offset (in points) at which to place the callout bubble.

This property determines the additional distance by which to move the callout bubble. When this property is set to (0, 0), the anchor point of the callout bubble is placed on the top-center point of the marker view’s frame. Specifying positive offset values moves the callout bubble down and to the right, while specifying negative values moves it up and to the left.

For Google Maps, see the `calloutAnchor` prop. 14 | | `anchor` | `Point` | (0.5, 1) | Sets the anchor point for the marker.

The anchor specifies the point in the icon image that is anchored to the marker's position on the Earth's surface.

The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) is the top-left corner of the image, and (1, 1) is the bottom-right corner. The anchoring point in a W x H image is the nearest discrete grid point in a (W + 1) x (H + 1) grid, obtained by scaling the then rounding. For example, in a 4 x 2 image, the anchor point (0.7, 0.6) resolves to the grid point at (3, 1).

For MapKit on iOS, see the `centerOffset` prop. 15 | | `calloutAnchor` | `Point` | (0.5, 0) | Specifies the point in the marker image at which to anchor the callout when it is displayed. This is specified in the same coordinate system as the anchor. See the `anchor` prop for more details.

The default is the top middle of the image. 16 | | `flat` | `Boolean` | false | Sets whether this marker should be flat against the map true or a billboard facing the camera. 17 | | `identifier` | `String` | | An identifier used to reference this marker at a later date. 18 | | `rotation` | `Float` | 0 | A float number indicating marker's rotation angle, in degrees. 19 | | `draggable` | `` | | This is a non-value based prop. Adding this allows the marker to be draggable (re-positioned). 20 | | `tracksViewChanges` | `Boolean` | true | Sets whether this marker should track view changes. It's recommended to turn it off whenever it's possible to improve custom marker performance. 21 | | `tracksInfoWindowChanges` | `Boolean` | false | Sets whether this marker should track view changes in info window. Enabling it will let marker change content of info window after first render pass, but will lead to decreased performance, so it's recommended to disable it whenever you don't need it. **Note**: iOS Google Maps only. 22 | | `opacity` | `Float` | 1.0 | The marker's opacity between 0.0 and 1.0. 23 | 24 | \* `ImageSource` [docs](https://reactnative.dev/docs/image#imagesource) 25 | 26 | ## Events 27 | 28 | To access event data, you will need to use `e.nativeEvent`. For example, `onPress={e => console.log(e.nativeEvent)}` will log the entire event object to your console. 29 | 30 | | Event Name | Returns | Notes 31 | |---|---|---| 32 | | `onPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when the user presses on the marker 33 | | `onSelect` | `{ coordinate: LatLng, position: Point }` | Callback that is called when the user selects the marker, before the callout is shown. **Note**: iOS only. 34 | | `onDeselect` | `{ coordinate: LatLng, position: Point }` | Callback that is called when the marker is deselected, before the callout is hidden. **Note**: iOS only. 35 | | `onCalloutPress` | | Callback that is called when the user taps the callout view. 36 | | `onDragStart` | `{ coordinate: LatLng, position: Point }` | Callback that is called when the user initiates a drag on this marker (if it is draggable) 37 | | `onDrag` | `{ coordinate: LatLng, position: Point }` | Callback called continuously as the marker is dragged 38 | | `onDragEnd` | `{ coordinate: LatLng, position: Point }` | Callback that is called when a drag on this marker finishes. This is usually the point you will want to setState on the marker's coordinate again 39 | 40 | 41 | ## Methods 42 | 43 | | Method Name | Arguments | Notes 44 | |---|---|---| 45 | | `showCallout` | | Shows the callout for this marker 46 | | `hideCallout` | | Hides the callout for this marker 47 | | `animateMarkerToCoordinate` | `coordinate: LatLng, duration: number` | Animates marker movement. 48 | | `redraw` | | Causes a redraw of the marker. Useful when there are updates to the marker and `tracksViewChanges` comes with a cost that is too high. 49 | 50 | 51 | 52 | ## Types 53 | 54 | ``` 55 | type LatLng { 56 | latitude: Number, 57 | longitude: Number, 58 | } 59 | ``` 60 | 61 | ``` 62 | type Point { 63 | x: Number, 64 | y: Number, 65 | } 66 | ``` 67 | 68 | ## Children Components 69 | 70 | Children components can be added within a Marker and rendered content will replace the marker symbol. This is a way of creating custom markers and allowing use of native SVGs. 71 | 72 | Example: 73 | ``` 74 | 75 | 76 | SF 77 | 78 | 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/polygon.md: -------------------------------------------------------------------------------- 1 | # `` Component API 2 | 3 | ## Props 4 | 5 | | Prop | Type | Default | Note | 6 | |---|---|---|---| 7 | | `coordinates` | `Array` | (Required) | An array of coordinates to describe the polygon 8 | | `holes` | `Array>` | | A 2d array of coordinates to describe holes of the polygon where each hole has at least 3 points. 9 | | `strokeWidth` | `Number` | `1` | The stroke width to use for the path. 10 | | `strokeColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The stroke color to use for the path. 11 | | `fillColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The fill color to use for the path. 12 | | `geodesic` | `Boolean` | | Boolean to indicate whether to draw each segment of the line as a geodesic as opposed to straight lines on the Mercator projection. A geodesic is the shortest path between two points on the Earth's surface. The geodesic curve is constructed assuming the Earth is a sphere. 13 | | `tappable` | `Bool` | `false` | Boolean to allow a polygon to be tappable and use the onPress function. 14 | 15 | ## Events 16 | 17 | | Event Name | Returns | Notes 18 | |---|---|---| 19 | | `onPress` | | Callback that is called when the user presses on the polygon 20 | 21 | ## Types 22 | 23 | ``` 24 | type LatLng { 25 | latitude: Number, 26 | longitude: Number, 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/polyline.md: -------------------------------------------------------------------------------- 1 | # `` Component API 2 | 3 | ## Props 4 | 5 | | Prop | Type | Default | Note | 6 | |---|---|---|---| 7 | | `coordinates` | `Array` | (Required) | An array of coordinates to describe the polyline 8 | | `strokeWidth` | `Number` | `1` | The stroke width to use for the path. 9 | | `strokeColor` | `String` | `#000, rgba(r,g,b,0.5)` | The stroke color to use for the path. 10 | | `strokeColors` | `Array` | `null` | The stroke colors to use for the path (iOS only). Must be the same length as `coordinates`. 11 | | `lineCap` | `String` | `round` | The line cap style to apply to the open ends of the path. Possible values are `butt`, `round` or `square`. Note: lineCap is not yet supported for GoogleMaps provider on iOS. 12 | | `geodesic` | `Boolean` | | Boolean to indicate whether to draw each segment of the line as a geodesic as opposed to straight lines on the Mercator projection. A geodesic is the shortest path between two points on the Earth's surface. The geodesic curve is constructed assuming the Earth is a sphere. 13 | | `lineDashPhase` | `Number` | `0` | (iOS only) The offset (in points) at which to start drawing the dash pattern. Use this property to start drawing a dashed line partway through a segment or gap. For example, a phase value of 6 for the patter 5-2-3-2 would cause drawing to begin in the middle of the first gap. 14 | | `lineDashPattern` | `Array` | `null` | An array of numbers specifying the dash pattern to use for the path. The array contains one or more numbers that indicate the lengths (measured in points) of the line segments and gaps in the pattern. The values in the array alternate, starting with the first line segment length, followed by the first gap length, followed by the second line segment length, and so on. 15 | | `tappable` | `Bool` | false | Boolean to allow a polyline to be tappable and use the onPress function. 16 | 17 | ## Events 18 | 19 | | Event Name | Returns | Notes 20 | |---|---|---| 21 | | `onPress` | | Callback that is called when the user presses on the polyline 22 | 23 | ## Types 24 | 25 | ``` 26 | type LatLng { 27 | latitude: Number, 28 | longitude: Number, 29 | } 30 | ``` 31 | 32 | ## Gradient Polylines (iOS MapKit only) 33 | 34 | Gradient polylines can be created by using the `strokeColors` prop. `strokeColors` must be an array with the same number of elements as `coordinates`. 35 | 36 | Example: 37 | 38 | ```js 39 | import MapView, { Polyline } from 'react-native-maps'; 40 | 41 | 42 | 62 | 63 | ``` 64 | -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /example/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.5 2 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby '2.7.5' 5 | 6 | gem 'cocoapods', '~> 1.11', '>= 1.11.2' 7 | -------------------------------------------------------------------------------- /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.osmdroidexample", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.osmdroidexample", 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_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/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/example/android/app/debug.keystore -------------------------------------------------------------------------------- /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 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/android/app/src/debug/java/com/osmdroidexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.osmdroidexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin; 21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 22 | import com.facebook.react.ReactInstanceEventListener; 23 | import com.facebook.react.ReactInstanceManager; 24 | import com.facebook.react.bridge.ReactContext; 25 | import com.facebook.react.modules.network.NetworkingModule; 26 | import okhttp3.OkHttpClient; 27 | 28 | public class ReactNativeFlipper { 29 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 30 | if (FlipperUtils.shouldEnableFlipper(context)) { 31 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 32 | 33 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 34 | client.addPlugin(new ReactFlipperPlugin()); 35 | client.addPlugin(new DatabasesFlipperPlugin(context)); 36 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 37 | client.addPlugin(CrashReporterPlugin.getInstance()); 38 | 39 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 40 | NetworkingModule.setCustomClientBuilder( 41 | new NetworkingModule.CustomClientBuilder() { 42 | @Override 43 | public void apply(OkHttpClient.Builder builder) { 44 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 45 | } 46 | }); 47 | client.addPlugin(networkFlipperPlugin); 48 | client.start(); 49 | 50 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 51 | // Hence we run if after all native modules have been initialized 52 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 53 | if (reactContext == null) { 54 | reactInstanceManager.addReactInstanceEventListener( 55 | new ReactInstanceEventListener() { 56 | @Override 57 | public void onReactContextInitialized(ReactContext reactContext) { 58 | reactInstanceManager.removeReactInstanceEventListener(this); 59 | reactContext.runOnNativeModulesQueueThread( 60 | new Runnable() { 61 | @Override 62 | public void run() { 63 | client.addPlugin(new FrescoFlipperPlugin()); 64 | } 65 | }); 66 | } 67 | }); 68 | } else { 69 | client.addPlugin(new FrescoFlipperPlugin()); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/osmdroidexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.osmdroidexample; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactActivityDelegate; 5 | import com.facebook.react.ReactRootView; 6 | 7 | public class MainActivity extends ReactActivity { 8 | 9 | /** 10 | * Returns the name of the main component registered from JavaScript. This is used to schedule 11 | * rendering of the component. 12 | */ 13 | @Override 14 | protected String getMainComponentName() { 15 | return "OsmdroidExample"; 16 | } 17 | 18 | /** 19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and 20 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer 21 | * (Paper). 22 | */ 23 | @Override 24 | protected ReactActivityDelegate createReactActivityDelegate() { 25 | return new MainActivityDelegate(this, getMainComponentName()); 26 | } 27 | 28 | public static class MainActivityDelegate extends ReactActivityDelegate { 29 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) { 30 | super(activity, mainComponentName); 31 | } 32 | 33 | @Override 34 | protected ReactRootView createRootView() { 35 | ReactRootView reactRootView = new ReactRootView(getContext()); 36 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 37 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); 38 | return reactRootView; 39 | } 40 | 41 | @Override 42 | protected boolean isConcurrentRootEnabled() { 43 | // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). 44 | // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html 45 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/osmdroidexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.osmdroidexample; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.facebook.react.PackageList; 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactInstanceManager; 8 | import com.facebook.react.ReactNativeHost; 9 | import com.facebook.react.ReactPackage; 10 | import com.facebook.react.config.ReactFeatureFlags; 11 | import com.facebook.soloader.SoLoader; 12 | import com.osmdroidexample.newarchitecture.MainApplicationReactNativeHost; 13 | import java.lang.reflect.InvocationTargetException; 14 | import java.util.List; 15 | 16 | public class MainApplication extends Application implements ReactApplication { 17 | 18 | private final ReactNativeHost mReactNativeHost = 19 | 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 | private final ReactNativeHost mNewArchitectureNativeHost = 41 | new MainApplicationReactNativeHost(this); 42 | 43 | @Override 44 | public ReactNativeHost getReactNativeHost() { 45 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 46 | return mNewArchitectureNativeHost; 47 | } else { 48 | return mReactNativeHost; 49 | } 50 | } 51 | 52 | @Override 53 | public void onCreate() { 54 | super.onCreate(); 55 | // If you opted-in for the New Architecture, we enable the TurboModule system 56 | ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 57 | SoLoader.init(this, /* native exopackage */ false); 58 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 59 | } 60 | 61 | /** 62 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like 63 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 64 | * 65 | * @param context 66 | * @param reactInstanceManager 67 | */ 68 | private static void initializeFlipper( 69 | Context context, ReactInstanceManager reactInstanceManager) { 70 | if (BuildConfig.DEBUG) { 71 | try { 72 | /* 73 | We use reflection here to pick up the class that initializes Flipper, 74 | since Flipper library is not available in release mode 75 | */ 76 | Class aClass = Class.forName("com.osmdroidexample.ReactNativeFlipper"); 77 | aClass 78 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) 79 | .invoke(null, context, reactInstanceManager); 80 | } catch (ClassNotFoundException e) { 81 | e.printStackTrace(); 82 | } catch (NoSuchMethodException e) { 83 | e.printStackTrace(); 84 | } catch (IllegalAccessException e) { 85 | e.printStackTrace(); 86 | } catch (InvocationTargetException e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/osmdroidexample/newarchitecture/MainApplicationReactNativeHost.java: -------------------------------------------------------------------------------- 1 | package com.osmdroidexample.newarchitecture; 2 | 3 | import android.app.Application; 4 | import androidx.annotation.NonNull; 5 | import com.facebook.react.PackageList; 6 | import com.facebook.react.ReactInstanceManager; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate; 10 | import com.facebook.react.bridge.JSIModulePackage; 11 | import com.facebook.react.bridge.JSIModuleProvider; 12 | import com.facebook.react.bridge.JSIModuleSpec; 13 | import com.facebook.react.bridge.JSIModuleType; 14 | import com.facebook.react.bridge.JavaScriptContextHolder; 15 | import com.facebook.react.bridge.ReactApplicationContext; 16 | import com.facebook.react.bridge.UIManager; 17 | import com.facebook.react.fabric.ComponentFactory; 18 | import com.facebook.react.fabric.CoreComponentsRegistry; 19 | import com.facebook.react.fabric.FabricJSIModuleProvider; 20 | import com.facebook.react.fabric.ReactNativeConfig; 21 | import com.facebook.react.uimanager.ViewManagerRegistry; 22 | import com.osmdroidexample.BuildConfig; 23 | import com.osmdroidexample.newarchitecture.components.MainComponentsRegistry; 24 | import com.osmdroidexample.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both 30 | * TurboModule delegates and the Fabric Renderer. 31 | * 32 | *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the 33 | * `newArchEnabled` property). Is ignored otherwise. 34 | */ 35 | public class MainApplicationReactNativeHost extends ReactNativeHost { 36 | public MainApplicationReactNativeHost(Application application) { 37 | super(application); 38 | } 39 | 40 | @Override 41 | public boolean getUseDeveloperSupport() { 42 | return BuildConfig.DEBUG; 43 | } 44 | 45 | @Override 46 | protected List getPackages() { 47 | List packages = new PackageList(this).getPackages(); 48 | // Packages that cannot be autolinked yet can be added manually here, for example: 49 | // packages.add(new MyReactNativePackage()); 50 | // TurboModules must also be loaded here providing a valid TurboReactPackage implementation: 51 | // packages.add(new TurboReactPackage() { ... }); 52 | // If you have custom Fabric Components, their ViewManagers should also be loaded here 53 | // inside a ReactPackage. 54 | return packages; 55 | } 56 | 57 | @Override 58 | protected String getJSMainModuleName() { 59 | return "index"; 60 | } 61 | 62 | @NonNull 63 | @Override 64 | protected ReactPackageTurboModuleManagerDelegate.Builder 65 | getReactPackageTurboModuleManagerDelegateBuilder() { 66 | // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary 67 | // for the new architecture and to use TurboModules correctly. 68 | return new MainApplicationTurboModuleManagerDelegate.Builder(); 69 | } 70 | 71 | @Override 72 | protected JSIModulePackage getJSIModulePackage() { 73 | return new JSIModulePackage() { 74 | @Override 75 | public List getJSIModules( 76 | final ReactApplicationContext reactApplicationContext, 77 | final JavaScriptContextHolder jsContext) { 78 | final List specs = new ArrayList<>(); 79 | 80 | // Here we provide a new JSIModuleSpec that will be responsible of providing the 81 | // custom Fabric Components. 82 | specs.add( 83 | new JSIModuleSpec() { 84 | @Override 85 | public JSIModuleType getJSIModuleType() { 86 | return JSIModuleType.UIManager; 87 | } 88 | 89 | @Override 90 | public JSIModuleProvider getJSIModuleProvider() { 91 | final ComponentFactory componentFactory = new ComponentFactory(); 92 | CoreComponentsRegistry.register(componentFactory); 93 | 94 | // Here we register a Components Registry. 95 | // The one that is generated with the template contains no components 96 | // and just provides you the one from React Native core. 97 | MainComponentsRegistry.register(componentFactory); 98 | 99 | final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); 100 | 101 | ViewManagerRegistry viewManagerRegistry = 102 | new ViewManagerRegistry( 103 | reactInstanceManager.getOrCreateViewManagers(reactApplicationContext)); 104 | 105 | return new FabricJSIModuleProvider( 106 | reactApplicationContext, 107 | componentFactory, 108 | ReactNativeConfig.DEFAULT_CONFIG, 109 | viewManagerRegistry); 110 | } 111 | }); 112 | return specs; 113 | } 114 | }; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/osmdroidexample/newarchitecture/components/MainComponentsRegistry.java: -------------------------------------------------------------------------------- 1 | package com.osmdroidexample.newarchitecture.components; 2 | 3 | import com.facebook.jni.HybridData; 4 | import com.facebook.proguard.annotations.DoNotStrip; 5 | import com.facebook.react.fabric.ComponentFactory; 6 | import com.facebook.soloader.SoLoader; 7 | 8 | /** 9 | * Class responsible to load the custom Fabric Components. This class has native methods and needs a 10 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ 11 | * folder for you). 12 | * 13 | *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the 14 | * `newArchEnabled` property). Is ignored otherwise. 15 | */ 16 | @DoNotStrip 17 | public class MainComponentsRegistry { 18 | static { 19 | SoLoader.loadLibrary("fabricjni"); 20 | } 21 | 22 | @DoNotStrip private final HybridData mHybridData; 23 | 24 | @DoNotStrip 25 | private native HybridData initHybrid(ComponentFactory componentFactory); 26 | 27 | @DoNotStrip 28 | private MainComponentsRegistry(ComponentFactory componentFactory) { 29 | mHybridData = initHybrid(componentFactory); 30 | } 31 | 32 | @DoNotStrip 33 | public static MainComponentsRegistry register(ComponentFactory componentFactory) { 34 | return new MainComponentsRegistry(componentFactory); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/osmdroidexample/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java: -------------------------------------------------------------------------------- 1 | package com.osmdroidexample.newarchitecture.modules; 2 | 3 | import com.facebook.jni.HybridData; 4 | import com.facebook.react.ReactPackage; 5 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.soloader.SoLoader; 8 | import java.util.List; 9 | 10 | /** 11 | * Class responsible to load the TurboModules. This class has native methods and needs a 12 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ 13 | * folder for you). 14 | * 15 | *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the 16 | * `newArchEnabled` property). Is ignored otherwise. 17 | */ 18 | public class MainApplicationTurboModuleManagerDelegate 19 | extends ReactPackageTurboModuleManagerDelegate { 20 | 21 | private static volatile boolean sIsSoLibraryLoaded; 22 | 23 | protected MainApplicationTurboModuleManagerDelegate( 24 | ReactApplicationContext reactApplicationContext, List packages) { 25 | super(reactApplicationContext, packages); 26 | } 27 | 28 | protected native HybridData initHybrid(); 29 | 30 | native boolean canCreateTurboModule(String moduleName); 31 | 32 | public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { 33 | protected MainApplicationTurboModuleManagerDelegate build( 34 | ReactApplicationContext context, List packages) { 35 | return new MainApplicationTurboModuleManagerDelegate(context, packages); 36 | } 37 | } 38 | 39 | @Override 40 | protected synchronized void maybeLoadOtherSoLibraries() { 41 | if (!sIsSoLibraryLoaded) { 42 | // If you change the name of your application .so file in the Android.mk file, 43 | // make sure you update the name here as well. 44 | SoLoader.loadLibrary("osmdroidexample_appmodules"); 45 | sIsSoLibraryLoaded = true; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | # Define the library name here. 4 | project(osmdroidexample_appmodules) 5 | 6 | # This file includes all the necessary to let you build your application with the New Architecture. 7 | include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/MainApplicationModuleProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "MainApplicationModuleProvider.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace facebook { 7 | namespace react { 8 | 9 | std::shared_ptr MainApplicationModuleProvider( 10 | const std::string &moduleName, 11 | const JavaTurboModule::InitParams ¶ms) { 12 | // Here you can provide your own module provider for TurboModules coming from 13 | // either your application or from external libraries. The approach to follow 14 | // is similar to the following (for a library called `samplelibrary`: 15 | // 16 | // auto module = samplelibrary_ModuleProvider(moduleName, params); 17 | // if (module != nullptr) { 18 | // return module; 19 | // } 20 | // return rncore_ModuleProvider(moduleName, params); 21 | 22 | // Module providers autolinked by RN CLI 23 | auto rncli_module = rncli_ModuleProvider(moduleName, params); 24 | if (rncli_module != nullptr) { 25 | return rncli_module; 26 | } 27 | 28 | return rncore_ModuleProvider(moduleName, params); 29 | } 30 | 31 | } // namespace react 32 | } // namespace facebook 33 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/MainApplicationModuleProvider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace facebook { 9 | namespace react { 10 | 11 | std::shared_ptr MainApplicationModuleProvider( 12 | const std::string &moduleName, 13 | const JavaTurboModule::InitParams ¶ms); 14 | 15 | } // namespace react 16 | } // namespace facebook 17 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "MainApplicationTurboModuleManagerDelegate.h" 2 | #include "MainApplicationModuleProvider.h" 3 | 4 | namespace facebook { 5 | namespace react { 6 | 7 | jni::local_ref 8 | MainApplicationTurboModuleManagerDelegate::initHybrid( 9 | jni::alias_ref) { 10 | return makeCxxInstance(); 11 | } 12 | 13 | void MainApplicationTurboModuleManagerDelegate::registerNatives() { 14 | registerHybrid({ 15 | makeNativeMethod( 16 | "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), 17 | makeNativeMethod( 18 | "canCreateTurboModule", 19 | MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), 20 | }); 21 | } 22 | 23 | std::shared_ptr 24 | MainApplicationTurboModuleManagerDelegate::getTurboModule( 25 | const std::string &name, 26 | const std::shared_ptr &jsInvoker) { 27 | // Not implemented yet: provide pure-C++ NativeModules here. 28 | return nullptr; 29 | } 30 | 31 | std::shared_ptr 32 | MainApplicationTurboModuleManagerDelegate::getTurboModule( 33 | const std::string &name, 34 | const JavaTurboModule::InitParams ¶ms) { 35 | return MainApplicationModuleProvider(name, params); 36 | } 37 | 38 | bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( 39 | const std::string &name) { 40 | return getTurboModule(name, nullptr) != nullptr || 41 | getTurboModule(name, {.moduleName = name}) != nullptr; 42 | } 43 | 44 | } // namespace react 45 | } // namespace facebook 46 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace facebook { 8 | namespace react { 9 | 10 | class MainApplicationTurboModuleManagerDelegate 11 | : public jni::HybridClass< 12 | MainApplicationTurboModuleManagerDelegate, 13 | TurboModuleManagerDelegate> { 14 | public: 15 | // Adapt it to the package you used for your Java class. 16 | static constexpr auto kJavaDescriptor = 17 | "Lcom/osmdroidexample/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; 18 | 19 | static jni::local_ref initHybrid(jni::alias_ref); 20 | 21 | static void registerNatives(); 22 | 23 | std::shared_ptr getTurboModule( 24 | const std::string &name, 25 | const std::shared_ptr &jsInvoker) override; 26 | std::shared_ptr getTurboModule( 27 | const std::string &name, 28 | const JavaTurboModule::InitParams ¶ms) override; 29 | 30 | /** 31 | * Test-only method. Allows user to verify whether a TurboModule can be 32 | * created by instances of this class. 33 | */ 34 | bool canCreateTurboModule(const std::string &name); 35 | }; 36 | 37 | } // namespace react 38 | } // namespace facebook 39 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/MainComponentsRegistry.cpp: -------------------------------------------------------------------------------- 1 | #include "MainComponentsRegistry.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace facebook { 10 | namespace react { 11 | 12 | MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} 13 | 14 | std::shared_ptr 15 | MainComponentsRegistry::sharedProviderRegistry() { 16 | auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); 17 | 18 | // Autolinked providers registered by RN CLI 19 | rncli_registerProviders(providerRegistry); 20 | 21 | // Custom Fabric Components go here. You can register custom 22 | // components coming from your App or from 3rd party libraries here. 23 | // 24 | // providerRegistry->add(concreteComponentDescriptorProvider< 25 | // AocViewerComponentDescriptor>()); 26 | return providerRegistry; 27 | } 28 | 29 | jni::local_ref 30 | MainComponentsRegistry::initHybrid( 31 | jni::alias_ref, 32 | ComponentFactory *delegate) { 33 | auto instance = makeCxxInstance(delegate); 34 | 35 | auto buildRegistryFunction = 36 | [](EventDispatcher::Weak const &eventDispatcher, 37 | ContextContainer::Shared const &contextContainer) 38 | -> ComponentDescriptorRegistry::Shared { 39 | auto registry = MainComponentsRegistry::sharedProviderRegistry() 40 | ->createComponentDescriptorRegistry( 41 | {eventDispatcher, contextContainer}); 42 | 43 | auto mutableRegistry = 44 | std::const_pointer_cast(registry); 45 | 46 | mutableRegistry->setFallbackComponentDescriptor( 47 | std::make_shared( 48 | ComponentDescriptorParameters{ 49 | eventDispatcher, contextContainer, nullptr})); 50 | 51 | return registry; 52 | }; 53 | 54 | delegate->buildRegistryFunction = buildRegistryFunction; 55 | return instance; 56 | } 57 | 58 | void MainComponentsRegistry::registerNatives() { 59 | registerHybrid({ 60 | makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), 61 | }); 62 | } 63 | 64 | } // namespace react 65 | } // namespace facebook 66 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/MainComponentsRegistry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace facebook { 9 | namespace react { 10 | 11 | class MainComponentsRegistry 12 | : public facebook::jni::HybridClass { 13 | public: 14 | // Adapt it to the package you used for your Java class. 15 | constexpr static auto kJavaDescriptor = 16 | "Lcom/osmdroidexample/newarchitecture/components/MainComponentsRegistry;"; 17 | 18 | static void registerNatives(); 19 | 20 | MainComponentsRegistry(ComponentFactory *delegate); 21 | 22 | private: 23 | static std::shared_ptr 24 | sharedProviderRegistry(); 25 | 26 | static jni::local_ref initHybrid( 27 | jni::alias_ref, 28 | ComponentFactory *delegate); 29 | }; 30 | 31 | } // namespace react 32 | } // namespace facebook 33 | -------------------------------------------------------------------------------- /example/android/app/src/main/jni/OnLoad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MainApplicationTurboModuleManagerDelegate.h" 3 | #include "MainComponentsRegistry.h" 4 | 5 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { 6 | return facebook::jni::initialize(vm, [] { 7 | facebook::react::MainApplicationTurboModuleManagerDelegate:: 8 | registerNatives(); 9 | facebook::react::MainComponentsRegistry::registerNatives(); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | OsmdroidExample 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 = "31.0.0" 6 | minSdkVersion = 21 7 | compileSdkVersion = 31 8 | targetSdkVersion = 31 9 | 10 | if (System.properties['os.arch'] == "aarch64") { 11 | // For M1 Users we need to use the NDK 24 which added support for aarch64 12 | ndkVersion = "24.0.8215888" 13 | } else { 14 | // Otherwise we default to the side-by-side NDK version from AGP. 15 | ndkVersion = "21.4.7075529" 16 | } 17 | } 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | dependencies { 23 | classpath("com.android.tools.build:gradle:7.2.1") 24 | classpath("com.facebook.react:react-native-gradle-plugin") 25 | classpath("de.undercouch:gradle-download-task:5.0.1") 26 | // NOTE: Do not place your application dependencies here; they belong 27 | // in the individual module build.gradle files 28 | } 29 | } 30 | 31 | allprojects { 32 | repositories { 33 | maven { 34 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 35 | url("$rootDir/../node_modules/react-native/android") 36 | } 37 | maven { 38 | // Android JSC is installed from npm 39 | url("$rootDir/../node_modules/jsc-android/dist") 40 | } 41 | mavenCentral { 42 | // We don't want to fetch react-native from Maven Central as there are 43 | // older versions over there. 44 | content { 45 | excludeGroup "com.facebook.react" 46 | } 47 | } 48 | google() 49 | maven { url 'https://www.jitpack.io' } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 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 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.174.0 29 | 30 | # Use this property to specify which architecture you want to build. 31 | # You can also override it from the CLI using 32 | # ./gradlew -PreactNativeArchitectures=x86_64 33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 34 | 35 | # Use this property to enable support to the new architecture. 36 | # This will allow you to use TurboModules and the Fabric render in 37 | # your application. You should enable this flag either if you want 38 | # to write custom TurboModules/Fabric components OR use libraries that 39 | # are providing them. 40 | newArchEnabled=false 41 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/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-7.5.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /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 https://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 Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'OsmdroidExample' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/react-native-gradle-plugin') 5 | 6 | if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { 7 | include(":ReactAndroid") 8 | project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') 9 | include(":ReactAndroid:hermes-engine") 10 | project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') 11 | } 12 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OsmdroidExample", 3 | "displayName": "OsmdroidExample" 4 | } -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:metro-react-native-babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /example/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /example/ios/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // OsmdroidExample 4 | // 5 | 6 | import Foundation 7 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample.xcodeproj/xcshareddata/xcschemes/OsmdroidExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic, strong) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | #import 5 | #import 6 | 7 | #import 8 | 9 | #if RCT_NEW_ARCH_ENABLED 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | 17 | #import 18 | 19 | static NSString *const kRNConcurrentRoot = @"concurrentRoot"; 20 | 21 | @interface AppDelegate () { 22 | RCTTurboModuleManager *_turboModuleManager; 23 | RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; 24 | std::shared_ptr _reactNativeConfig; 25 | facebook::react::ContextContainer::Shared _contextContainer; 26 | } 27 | @end 28 | #endif 29 | 30 | @implementation AppDelegate 31 | 32 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 33 | { 34 | RCTAppSetupPrepareApp(application); 35 | 36 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 37 | 38 | #if RCT_NEW_ARCH_ENABLED 39 | _contextContainer = std::make_shared(); 40 | _reactNativeConfig = std::make_shared(); 41 | _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); 42 | _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; 43 | bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; 44 | #endif 45 | 46 | NSDictionary *initProps = [self prepareInitialProps]; 47 | UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"OsmdroidExample", initProps); 48 | 49 | if (@available(iOS 13.0, *)) { 50 | rootView.backgroundColor = [UIColor systemBackgroundColor]; 51 | } else { 52 | rootView.backgroundColor = [UIColor whiteColor]; 53 | } 54 | 55 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 56 | UIViewController *rootViewController = [UIViewController new]; 57 | rootViewController.view = rootView; 58 | self.window.rootViewController = rootViewController; 59 | [self.window makeKeyAndVisible]; 60 | return YES; 61 | } 62 | 63 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. 64 | /// 65 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html 66 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). 67 | /// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. 68 | - (BOOL)concurrentRootEnabled 69 | { 70 | // Switch this bool to turn on and off the concurrent root 71 | return true; 72 | } 73 | 74 | - (NSDictionary *)prepareInitialProps 75 | { 76 | NSMutableDictionary *initProps = [NSMutableDictionary new]; 77 | 78 | #ifdef RCT_NEW_ARCH_ENABLED 79 | initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); 80 | #endif 81 | 82 | return initProps; 83 | } 84 | 85 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 86 | { 87 | #if DEBUG 88 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 89 | #else 90 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 91 | #endif 92 | } 93 | 94 | #if RCT_NEW_ARCH_ENABLED 95 | 96 | #pragma mark - RCTCxxBridgeDelegate 97 | 98 | - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge 99 | { 100 | _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge 101 | delegate:self 102 | jsInvoker:bridge.jsCallInvoker]; 103 | return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); 104 | } 105 | 106 | #pragma mark RCTTurboModuleManagerDelegate 107 | 108 | - (Class)getModuleClassFromName:(const char *)name 109 | { 110 | return RCTCoreModulesClassProvider(name); 111 | } 112 | 113 | - (std::shared_ptr)getTurboModule:(const std::string &)name 114 | jsInvoker:(std::shared_ptr)jsInvoker 115 | { 116 | return nullptr; 117 | } 118 | 119 | - (std::shared_ptr)getTurboModule:(const std::string &)name 120 | initParams: 121 | (const facebook::react::ObjCTurboModule::InitParams &)params 122 | { 123 | return nullptr; 124 | } 125 | 126 | - (id)getModuleInstanceFromClass:(Class)moduleClass 127 | { 128 | return RCTAppSetupDefaultModuleFromClass(moduleClass); 129 | } 130 | 131 | #endif 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | OsmdroidExample 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 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/ios/OsmdroidExampleTests/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/OsmdroidExampleTests/OsmdroidExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface OsmdroidExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation OsmdroidExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | platform :ios, '12.4' 5 | install! 'cocoapods', :deterministic_uuids => false 6 | 7 | target 'OsmdroidExample' do 8 | config = use_native_modules! 9 | 10 | # Flags change depending on the env values. 11 | flags = get_default_flags() 12 | 13 | use_react_native!( 14 | :path => config[:reactNativePath], 15 | # Hermes is now enabled by default. Disable by setting this flag to false. 16 | # Upcoming versions of React Native may rely on get_default_flags(), but 17 | # we make it explicit here to aid in the React Native upgrade process. 18 | :hermes_enabled => true, 19 | :fabric_enabled => flags[:fabric_enabled], 20 | # Enables Flipper. 21 | # 22 | # Note that if you have use_frameworks! enabled, Flipper will not work and 23 | # you should disable the next line. 24 | :flipper_configuration => FlipperConfiguration.enabled, 25 | # An absolute path to your application root. 26 | :app_path => "#{Pod::Config.instance.installation_root}/.." 27 | ) 28 | 29 | target 'OsmdroidExampleTests' do 30 | inherit! :complete 31 | # Pods for testing 32 | end 33 | 34 | post_install do |installer| 35 | react_native_post_install( 36 | installer, 37 | # Set `mac_catalyst_enabled` to `true` in order to apply patches 38 | # necessary for Mac Catalyst builds 39 | :mac_catalyst_enabled => false 40 | ) 41 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const escape = require('escape-string-regexp'); 3 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 4 | const pak = require('../package.json'); 5 | 6 | const root = path.resolve(__dirname, '..'); 7 | 8 | const modules = Object.keys({ 9 | ...pak.peerDependencies, 10 | }); 11 | 12 | module.exports = { 13 | projectRoot: __dirname, 14 | watchFolders: [root], 15 | 16 | // We need to make sure that only one version is loaded for peerDependencies 17 | // So we block them at the root, and alias them to the versions in example's node_modules 18 | resolver: { 19 | blacklistRE: exclusionList( 20 | modules.map( 21 | (m) => 22 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 23 | ) 24 | ), 25 | 26 | extraNodeModules: modules.reduce((acc, name) => { 27 | acc[name] = path.join(__dirname, 'node_modules', name); 28 | return acc; 29 | }, {}), 30 | }, 31 | 32 | transformer: { 33 | getTransformOptions: async () => ({ 34 | transform: { 35 | experimentalImportSupport: false, 36 | inlineRequires: true, 37 | }, 38 | }), 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OsmdroidExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "pods": "pod-install --quiet" 10 | }, 11 | "dependencies": { 12 | "react": "18.1.0", 13 | "react-native": "0.70.6" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.12.9", 17 | "@babel/runtime": "^7.12.5", 18 | "metro-react-native-babel-preset": "0.72.3", 19 | "babel-plugin-module-resolver": "^4.1.0" 20 | } 21 | } -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; 4 | import MapView, { 5 | Circle, 6 | Marker, 7 | Polygon, 8 | Polyline, 9 | Region, 10 | UrlTile, 11 | } from '@splicer97/react-native-osmdroid'; 12 | 13 | export default function App() { 14 | const initialRegion: Region = { 15 | latitude: 55.75222, 16 | longitude: 37.61556, 17 | latitudeDelta: 0.5, 18 | longitudeDelta: 0.5, 19 | }; 20 | const toner = 21 | 'https://api.maptiler.com/maps/toner-v2/{z}/{x}/{y}.png?key=j46yoHMlBMQRgTY3lCMk'; 22 | const mapRef = React.useRef(); 23 | const zelenograd: Region = { 24 | latitude: 55.9825, 25 | longitude: 37.18139, 26 | latitudeDelta: 0.5, 27 | longitudeDelta: 0.5, 28 | }; 29 | const goHome = () => { 30 | mapRef.current?.animateToRegion(zelenograd); 31 | }; 32 | return ( 33 | 34 | { 39 | console.log('🚀 ~ file: App.tsx:117 ~ App ~ onRegionChange:', event); 40 | }} 41 | onRegionChangeComplete={(event) => { 42 | console.log('🚀 ~ file: App.tsx:117 ~ App ~ onRegionChange:', event); 43 | }} 44 | > 45 | 51 | 52 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem 53 | blanditiis nobis, assumenda ipsam ex cupiditate delectus inventore 54 | labore autem optio eum illo adipisci exercitationem quas incidunt 55 | distinctio! Iure, ex quisquam! 56 | 57 | 58 | 80 | 98 | 107 | 108 | 109 | 121 | 122 | ); 123 | } 124 | 125 | const styles = StyleSheet.create({ 126 | container: { 127 | ...StyleSheet.absoluteFillObject, 128 | }, 129 | }); 130 | -------------------------------------------------------------------------------- /images/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/images/circle.png -------------------------------------------------------------------------------- /images/mapView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/images/mapView.png -------------------------------------------------------------------------------- /images/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/images/marker.png -------------------------------------------------------------------------------- /images/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/images/polygon.png -------------------------------------------------------------------------------- /images/polyline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/images/polyline.png -------------------------------------------------------------------------------- /images/urlTile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Splicer97/react-native-osmdroid/5eceda08c0cbd2b5e14f8f55150274e38500949f/images/urlTile.png -------------------------------------------------------------------------------- /lefthook.yml: -------------------------------------------------------------------------------- 1 | pre-commit: 2 | parallel: true 3 | commands: 4 | lint: 5 | files: git diff --name-only @{push} 6 | glob: "*.{js,ts,jsx,tsx}" 7 | run: npx eslint {files} 8 | types: 9 | files: git diff --name-only @{push} 10 | glob: "*.{js,ts, jsx, tsx}" 11 | run: npx tsc --noEmit 12 | commit-msg: 13 | parallel: true 14 | commands: 15 | commitlint: 16 | run: npx commitlint --edit 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@splicer97/react-native-osmdroid", 3 | "version": "0.14.1", 4 | "description": "This is unofficial React Native wrapper for osmdroid maps", 5 | "main": "lib/commonjs/index", 6 | "module": "lib/module/index", 7 | "types": "lib/typescript/index.d.ts", 8 | "react-native": "src/index", 9 | "source": "src/index", 10 | "files": [ 11 | "src", 12 | "lib", 13 | "android", 14 | "ios", 15 | "cpp", 16 | "*.podspec", 17 | "!lib/typescript/example", 18 | "!ios/build", 19 | "!android/build", 20 | "!android/gradle", 21 | "!android/gradlew", 22 | "!android/gradlew.bat", 23 | "!android/local.properties", 24 | "!**/__tests__", 25 | "!**/__fixtures__", 26 | "!**/__mocks__", 27 | "!**/.*" 28 | ], 29 | "scripts": { 30 | "test": "jest", 31 | "typecheck": "tsc --noEmit", 32 | "lint": "eslint \"**/*.{js,ts,tsx}\"", 33 | "prepack": "bob build", 34 | "release": "release-it", 35 | "example": "yarn --cwd example", 36 | "bootstrap": "yarn example && yarn install && yarn example pods", 37 | "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build" 38 | }, 39 | "keywords": [ 40 | "react-native", 41 | "react", 42 | "maps", 43 | "osmdroid", 44 | "open-street-maps", 45 | "osm", 46 | "android" 47 | ], 48 | "repository": "https://github.com/Splicer97/react-native-osmdroid", 49 | "author": "Nikita_Kovantsov (https://github.com/Splicer97)", 50 | "license": "MIT", 51 | "bugs": { 52 | "url": "https://github.com/Splicer97/react-native-osmdroid/issues" 53 | }, 54 | "homepage": "https://github.com/Splicer97/react-native-osmdroid#readme", 55 | "publishConfig": { 56 | "registry": "https://registry.npmjs.org/" 57 | }, 58 | "dependencies": { 59 | "@types/geojson": "^7946.0.10" 60 | }, 61 | "devDependencies": { 62 | "@evilmartians/lefthook": "^1.2.2", 63 | "@commitlint/config-conventional": "^17.0.2", 64 | "@react-native-community/eslint-config": "^3.0.2", 65 | "@release-it/conventional-changelog": "^5.0.0", 66 | "@types/jest": "^28.1.2", 67 | "@types/react": "~17.0.21", 68 | "@types/react-native": "0.70.0", 69 | "commitlint": "^17.0.2", 70 | "del-cli": "^5.0.0", 71 | "eslint": "^8.4.1", 72 | "eslint-config-prettier": "^8.5.0", 73 | "eslint-plugin-prettier": "^4.0.0", 74 | "jest": "^28.1.1", 75 | "pod-install": "^0.1.0", 76 | "prettier": "^2.0.5", 77 | "react": "18.1.0", 78 | "react-native": "0.70.6", 79 | "react-native-builder-bob": "^0.20.0", 80 | "release-it": "^15.0.0", 81 | "typescript": "^4.5.2" 82 | }, 83 | "resolutions": { 84 | "@types/react": "17.0.21" 85 | }, 86 | "peerDependencies": { 87 | "react": "*", 88 | "react-native": "*" 89 | }, 90 | "engines": { 91 | "node": ">= 16.0.0" 92 | }, 93 | "packageManager": "^yarn@1.22.15", 94 | "jest": { 95 | "preset": "react-native", 96 | "modulePathIgnorePatterns": [ 97 | "/example/node_modules", 98 | "/lib/" 99 | ] 100 | }, 101 | "commitlint": { 102 | "extends": [ 103 | "@commitlint/config-conventional" 104 | ] 105 | }, 106 | "release-it": { 107 | "git": { 108 | "commitMessage": "chore: release ${version}", 109 | "tagName": "v${version}" 110 | }, 111 | "npm": { 112 | "publish": true 113 | }, 114 | "github": { 115 | "release": true 116 | }, 117 | "plugins": { 118 | "@release-it/conventional-changelog": { 119 | "preset": "angular" 120 | } 121 | } 122 | }, 123 | "eslintConfig": { 124 | "root": true, 125 | "extends": [ 126 | "@react-native-community", 127 | "prettier" 128 | ], 129 | "rules": { 130 | "prettier/prettier": [ 131 | "error", 132 | { 133 | "quoteProps": "consistent", 134 | "singleQuote": true, 135 | "tabWidth": 2, 136 | "trailingComma": "es5", 137 | "useTabs": false 138 | } 139 | ] 140 | } 141 | }, 142 | "eslintIgnore": [ 143 | "node_modules/", 144 | "lib/" 145 | ], 146 | "prettier": { 147 | "quoteProps": "consistent", 148 | "singleQuote": true, 149 | "tabWidth": 2, 150 | "trailingComma": "es5", 151 | "useTabs": false 152 | }, 153 | "react-native-builder-bob": { 154 | "source": "src", 155 | "output": "lib", 156 | "targets": [ 157 | "commonjs", 158 | "module", 159 | [ 160 | "typescript", 161 | { 162 | "project": "tsconfig.build.json" 163 | } 164 | ] 165 | ] 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const path = require('path'); 3 | const child_process = require('child_process'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | const args = process.argv.slice(2); 7 | const options = { 8 | cwd: process.cwd(), 9 | env: process.env, 10 | stdio: 'inherit', 11 | encoding: 'utf-8', 12 | }; 13 | 14 | if (os.type() === 'Windows_NT') { 15 | options.shell = true; 16 | } 17 | 18 | let result; 19 | 20 | if (process.cwd() !== root || args.length) { 21 | // We're not in the root of the project, or additional arguments were passed 22 | // In this case, forward the command to `yarn` 23 | result = child_process.spawnSync('yarn', args, options); 24 | } else { 25 | // If `yarn` is run without arguments, perform bootstrap 26 | result = child_process.spawnSync('yarn', ['bootstrap'], options); 27 | } 28 | 29 | process.exitCode = result.status; 30 | -------------------------------------------------------------------------------- /src/AnimatedRegion.ts: -------------------------------------------------------------------------------- 1 | import { Animated } from 'react-native'; 2 | import type { Region } from './sharedTypes'; 3 | 4 | const AnimatedWithChildren = Object.getPrototypeOf(Animated.ValueXY); 5 | if (__DEV__) { 6 | if (AnimatedWithChildren.name !== 'AnimatedWithChildren') { 7 | console.error( 8 | 'AnimatedRegion could not obtain AnimatedWithChildren base class' 9 | ); 10 | } 11 | } 12 | 13 | const configTypes: (keyof Region)[] = [ 14 | 'latitude', 15 | 'longitude', 16 | 'latitudeDelta', 17 | 'longitudeDelta', 18 | ]; 19 | 20 | const defaultValues = { 21 | // probably want to come up with better defaults 22 | latitude: 0, 23 | longitude: 0, 24 | latitudeDelta: 0, 25 | longitudeDelta: 0, 26 | }; 27 | 28 | let _uniqueId = 1; 29 | 30 | type TValueIn = number | Animated.Value | undefined; 31 | 32 | type Props = Partial | undefined; 33 | 34 | const getAnimatedValue = (valueIn: TValueIn, fallback: number) => { 35 | if (valueIn instanceof Animated.Value) { 36 | return valueIn; 37 | } else if (typeof valueIn === 'number') { 38 | return new Animated.Value(valueIn); 39 | } 40 | return new Animated.Value(fallback); 41 | }; 42 | 43 | export default class AnimatedMapRegion extends AnimatedWithChildren { 44 | constructor(valueIn: Props = {}) { 45 | super(); 46 | this.latitude = getAnimatedValue(valueIn.latitude, defaultValues.latitude); 47 | this.longitude = getAnimatedValue( 48 | valueIn.longitude, 49 | defaultValues.longitude 50 | ); 51 | this.latitudeDelta = getAnimatedValue( 52 | valueIn.latitudeDelta, 53 | defaultValues.latitudeDelta 54 | ); 55 | this.longitudeDelta = getAnimatedValue( 56 | valueIn.longitudeDelta, 57 | defaultValues.longitudeDelta 58 | ); 59 | this._regionListeners = {}; 60 | } 61 | 62 | setValue(value: Region) { 63 | this.latitude._value = value.latitude; 64 | this.longitude._value = value.longitude; 65 | this.latitudeDelta._value = value.latitudeDelta; 66 | this.longitudeDelta._value = value.longitudeDelta; 67 | } 68 | 69 | setOffset(offset: Region) { 70 | this.latitude.setOffset(offset.latitude); 71 | this.longitude.setOffset(offset.longitude); 72 | this.latitudeDelta.setOffset(offset.latitudeDelta); 73 | this.longitudeDelta.setOffset(offset.longitudeDelta); 74 | } 75 | 76 | flattenOffset() { 77 | this.latitude.flattenOffset(); 78 | this.longitude.flattenOffset(); 79 | this.latitudeDelta.flattenOffset(); 80 | this.longitudeDelta.flattenOffset(); 81 | } 82 | 83 | private __getValue() { 84 | return { 85 | latitude: this.latitude.__getValue(), 86 | longitude: this.longitude.__getValue(), 87 | latitudeDelta: this.latitudeDelta.__getValue(), 88 | longitudeDelta: this.longitudeDelta.__getValue(), 89 | }; 90 | } 91 | 92 | // private __attach() { 93 | // this.latitude.__addChild(this); 94 | // this.longitude.__addChild(this); 95 | // this.latitudeDelta.__addChild(this); 96 | // this.longitudeDelta.__addChild(this); 97 | // } 98 | 99 | // private __detach() { 100 | // this.latitude.__removeChild(this); 101 | // this.longitude.__removeChild(this); 102 | // this.latitudeDelta.__removeChild(this); 103 | // this.longitudeDelta.__removeChild(this); 104 | // } 105 | 106 | stopAnimation(callback: (region: Region) => void) { 107 | this.latitude.stopAnimation(); 108 | this.longitude.stopAnimation(); 109 | this.latitudeDelta.stopAnimation(); 110 | this.longitudeDelta.stopAnimation(); 111 | callback && callback(this.__getValue()); 112 | } 113 | 114 | addListener(callback: (region: Region) => void) { 115 | const id = String(_uniqueId++); 116 | const jointCallback = () => /*{value}*/ callback(this.__getValue()); 117 | this._regionListeners[id] = { 118 | latitude: this.latitude.addListener(jointCallback), 119 | longitude: this.longitude.addListener(jointCallback), 120 | latitudeDelta: this.latitudeDelta.addListener(jointCallback), 121 | longitudeDelta: this.longitudeDelta.addListener(jointCallback), 122 | }; 123 | return id; 124 | } 125 | 126 | removeListener(id: string) { 127 | this.latitude.removeListener(this._regionListeners[id].latitude); 128 | this.longitude.removeListener(this._regionListeners[id].longitude); 129 | this.latitudeDelta.removeListener(this._regionListeners[id].latitudeDelta); 130 | this.longitudeDelta.removeListener( 131 | this._regionListeners[id].longitudeDelta 132 | ); 133 | delete this._regionListeners[id]; 134 | } 135 | 136 | spring(config: Animated.SpringAnimationConfig & Region) { 137 | const animations = []; 138 | for (const type of configTypes) { 139 | if (config.hasOwnProperty(type)) { 140 | animations.push( 141 | Animated.spring(this[type], { 142 | ...config, 143 | toValue: config[type], 144 | // may help to eliminate some dev warnings and perf issues 145 | useNativeDriver: !!config?.useNativeDriver, 146 | }) 147 | ); 148 | } 149 | } 150 | return Animated.parallel(animations); 151 | } 152 | 153 | timing(config: Animated.TimingAnimationConfig & Region) { 154 | const animations = []; 155 | for (const type of configTypes) { 156 | if (config.hasOwnProperty(type)) { 157 | animations.push( 158 | Animated.timing(this[type], { 159 | ...config, 160 | toValue: config[type], 161 | // may help to eliminate some dev warnings and perf issues 162 | useNativeDriver: !!config?.useNativeDriver, 163 | }) 164 | ); 165 | } 166 | } 167 | return Animated.parallel(animations); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/MapCallout.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { requireNativeComponent, StyleSheet, ViewProps } from 'react-native'; 3 | import type { CalloutPressEvent } from './sharedTypes'; 4 | 5 | export type MapCalloutProps = ViewProps & { 6 | /** 7 | * Callback that is called when the user presses on the callout 8 | * 9 | */ 10 | onPress?: (event: CalloutPressEvent) => void; 11 | 12 | /** 13 | * If `false`, a default "tooltip" bubble window will be drawn around this callouts children. 14 | * If `true`, the child views can fully customize their appearance, including any "bubble" like styles. 15 | * 16 | * @default false 17 | */ 18 | tooltip?: boolean; 19 | }; 20 | 21 | type NativeProps = MapCalloutProps; 22 | 23 | class MapCallout extends React.Component { 24 | render() { 25 | const { tooltip = false } = this.props; 26 | return ( 27 | 32 | ); 33 | } 34 | } 35 | 36 | const styles = StyleSheet.create({ 37 | callout: { 38 | position: 'absolute', 39 | }, 40 | }); 41 | 42 | const OsmMapCallout = requireNativeComponent('OsmMapCallout'); 43 | 44 | export default MapCallout; 45 | -------------------------------------------------------------------------------- /src/MapCircle.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { requireNativeComponent, View, ViewProps } from 'react-native'; 3 | import type { NativeComponent } from './decorateMapComponent'; 4 | import type { LatLng } from './sharedTypes'; 5 | 6 | export type MapCircleProps = ViewProps & { 7 | /** 8 | * The coordinates of the center of the circle. 9 | * 10 | */ 11 | center: LatLng; 12 | 13 | /** 14 | * The fill color to use for the path. 15 | * 16 | * @default `#000`, `rgba(r,g,b,0.5)` 17 | */ 18 | fillColor?: string; 19 | 20 | /** 21 | * The radius of the circle to be drawn (in meters) 22 | * 23 | */ 24 | radius: number; 25 | 26 | /** 27 | * The stroke color to use for the path. 28 | * 29 | * @default `#000`, `rgba(r,g,b,0.5)` 30 | */ 31 | strokeColor?: string; 32 | 33 | /** 34 | * The stroke width to use for the path. 35 | * 36 | * @default 1 37 | */ 38 | strokeWidth?: number; 39 | }; 40 | 41 | type NativeProps = MapCircleProps & { ref: React.RefObject }; 42 | 43 | class MapCircle extends React.Component { 44 | private circle: NativeProps['ref']; 45 | 46 | constructor(props: MapCircleProps) { 47 | super(props); 48 | this.circle = React.createRef(); 49 | } 50 | 51 | setNativeProps(props: Partial) { 52 | this.circle.current?.setNativeProps(props); 53 | } 54 | 55 | render() { 56 | const { strokeColor = '#000', strokeWidth = 1 } = this.props; 57 | 58 | return ( 59 | 65 | ); 66 | } 67 | } 68 | 69 | const OsmMapCircle: NativeComponent = 70 | requireNativeComponent('OsmMapCircle'); 71 | 72 | export default MapCircle; 73 | -------------------------------------------------------------------------------- /src/MapMarkerNativeComponent.ts: -------------------------------------------------------------------------------- 1 | import type { HostComponent } from 'react-native'; 2 | import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; 3 | import type { NativeProps } from './MapMarker'; 4 | import type { LatLng } from './sharedTypes'; 5 | 6 | export type MapMarkerNativeComponentType = HostComponent; 7 | 8 | interface NativeCommands { 9 | showCallout: ( 10 | viewRef: NonNullable< 11 | React.RefObject['current'] 12 | > 13 | ) => void; 14 | hideCallout: ( 15 | viewRef: NonNullable< 16 | React.RefObject['current'] 17 | > 18 | ) => void; 19 | redrawCallout: ( 20 | viewRef: NonNullable< 21 | React.RefObject['current'] 22 | > 23 | ) => void; 24 | animateMarkerToCoordinate: ( 25 | viewRef: NonNullable< 26 | React.RefObject['current'] 27 | >, 28 | coordinate: LatLng, 29 | duration: number 30 | ) => void; 31 | redraw: ( 32 | viewRef: NonNullable< 33 | React.RefObject['current'] 34 | > 35 | ) => void; 36 | } 37 | 38 | export const Commands: NativeCommands = codegenNativeCommands({ 39 | supportedCommands: [ 40 | 'showCallout', 41 | 'hideCallout', 42 | 'redrawCallout', 43 | 'animateMarkerToCoordinate', 44 | 'redraw', 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /src/MapPolygon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | NativeSyntheticEvent, 4 | requireNativeComponent, 5 | View, 6 | ViewProps, 7 | } from 'react-native'; 8 | import type { NativeComponent } from './decorateMapComponent'; 9 | import type { LatLng, Point } from './sharedTypes'; 10 | 11 | export type MapPolygonProps = ViewProps & { 12 | /** 13 | * An array of coordinates to describe the polygon 14 | * 15 | */ 16 | coordinates: LatLng[]; 17 | 18 | /** 19 | * The fill color to use for the path. 20 | * 21 | * @default `#000`, `rgba(r,g,b,0.5)` 22 | */ 23 | fillColor?: string; 24 | 25 | /** 26 | * Boolean to indicate whether to draw each segment of the line as a geodesic as opposed to straight lines on the Mercator projection. 27 | * A geodesic is the shortest path between two points on the Earth's surface. 28 | * The geodesic curve is constructed assuming the Earth is a sphere. 29 | * 30 | */ 31 | geodesic?: boolean; 32 | 33 | /** 34 | * A 2d array of coordinates to describe holes of the polygon where each hole has at least 3 points. 35 | * 36 | */ 37 | holes?: LatLng[][]; 38 | 39 | /** 40 | * Callback that is called when the user presses on the polygon 41 | * 42 | */ 43 | onPress?: (event: PolygonPressEvent) => void; 44 | 45 | /** 46 | * The stroke color to use for the path. 47 | * 48 | * @default `#000`, `rgba(r,g,b,0.5)` 49 | */ 50 | strokeColor?: string; 51 | 52 | /** 53 | * The stroke width to use for the path. 54 | * 55 | * @default 1 56 | */ 57 | strokeWidth?: number; 58 | 59 | /** 60 | * Boolean to allow a polygon to be tappable and use the onPress function. 61 | * 62 | */ 63 | tappable?: boolean; 64 | }; 65 | 66 | type PolygonPressEvent = NativeSyntheticEvent<{ 67 | action: 'polygon-press'; 68 | id?: string; 69 | coordinate?: LatLng; 70 | position?: Point; 71 | }>; 72 | 73 | type NativeProps = MapPolygonProps & { ref: React.RefObject }; 74 | 75 | class MapPolygon extends React.Component { 76 | private polygon: NativeProps['ref']; 77 | 78 | constructor(props: MapPolygonProps) { 79 | super(props); 80 | this.polygon = React.createRef(); 81 | } 82 | 83 | setNativeProps(props: Partial) { 84 | this.polygon.current?.setNativeProps(props); 85 | } 86 | 87 | render() { 88 | const { strokeColor = '#000', strokeWidth = 1 } = this.props; 89 | return ( 90 | 96 | ); 97 | } 98 | } 99 | 100 | const OsmMapPolygon: NativeComponent = 101 | requireNativeComponent('OsmMapPolygon'); 102 | 103 | export default MapPolygon; 104 | -------------------------------------------------------------------------------- /src/MapPolyline.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | NativeSyntheticEvent, 4 | requireNativeComponent, 5 | View, 6 | ViewProps, 7 | } from 'react-native'; 8 | import type { NativeComponent } from './decorateMapComponent'; 9 | import type { LatLng, LineCapType, Point } from './sharedTypes'; 10 | 11 | export type MapPolylineProps = ViewProps & { 12 | /** 13 | * An array of coordinates to describe the polyline 14 | */ 15 | coordinates: LatLng[]; 16 | 17 | /** 18 | * The fill color to use for the path. 19 | * 20 | * @default `#000`, `rgba(r,g,b,0.5)` 21 | */ 22 | fillColor?: string; 23 | 24 | /** 25 | * Boolean to indicate whether to draw each segment of the line as a geodesic as opposed to straight lines on the Mercator projection. 26 | * A geodesic is the shortest path between two points on the Earth's surface. 27 | * The geodesic curve is constructed assuming the Earth is a sphere. 28 | */ 29 | geodesic?: boolean; 30 | 31 | /** 32 | * The line cap style to apply to the open ends of the path 33 | * 34 | * @default `round` 35 | */ 36 | lineCap?: LineCapType; 37 | 38 | /** 39 | * An array of numbers specifying the dash pattern to use for the path. 40 | * The array contains one or more numbers that indicate the lengths (measured in points) 41 | * of the line segments and gaps in the pattern. 42 | * The values in the array alternate, starting with the first line segment length, 43 | * followed by the first gap length, followed by the second line segment length, and so on. 44 | */ 45 | lineDashPattern?: number[]; 46 | 47 | /** 48 | * Callback that is called when the user presses on the polyline 49 | */ 50 | onPress?: (event: PolylinePressEvent) => void; 51 | 52 | /** 53 | * The stroke color to use for the path. 54 | * 55 | * @default `#000`, `rgba(r,g,b,0.5)` 56 | */ 57 | strokeColor?: string; 58 | 59 | /** 60 | * The stroke colors to use for the path. 61 | * 62 | * Must be the same length as `coordinates` 63 | */ 64 | strokeColors?: string[]; 65 | 66 | /** 67 | * The stroke width to use for the path. 68 | * 69 | * @default 1 70 | */ 71 | strokeWidth?: number; 72 | 73 | /** 74 | * Boolean to allow the polyline to be tappable and use the onPress function. 75 | */ 76 | tappable?: boolean; 77 | }; 78 | 79 | export type PolylinePressEvent = NativeSyntheticEvent<{ 80 | action: 'polyline-press'; 81 | id?: string; 82 | coordinate?: LatLng; 83 | position?: Point; 84 | }>; 85 | 86 | type NativeProps = MapPolylineProps & { ref: React.RefObject }; 87 | 88 | class MapPolyline extends React.Component { 89 | private polyline: NativeProps['ref']; 90 | 91 | constructor(props: MapPolylineProps) { 92 | super(props); 93 | this.polyline = React.createRef(); 94 | } 95 | 96 | setNativeProps(props: Partial) { 97 | this.polyline.current?.setNativeProps(props); 98 | } 99 | 100 | render() { 101 | const { 102 | strokeColor = '#000', 103 | strokeWidth = 1, 104 | lineCap = 'round', 105 | } = this.props; 106 | 107 | return ( 108 | 115 | ); 116 | } 117 | } 118 | 119 | const OsmMapPolyline: NativeComponent = 120 | requireNativeComponent('OsmMapPolyline'); 121 | 122 | export default MapPolyline; 123 | -------------------------------------------------------------------------------- /src/MapUrlTile.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { requireNativeComponent, ViewProps } from 'react-native'; 4 | 5 | export type MapUrlTileProps = ViewProps & { 6 | /** 7 | * Doubles tile size from 256 to 512 utilising higher zoom levels 8 | * i.e loading 4 higher zoom level tiles and combining them for one high-resolution tile. 9 | * NB! using this makes text labels smaller than in the original map style. 10 | * 11 | */ 12 | doubleTileSize?: boolean; 13 | 14 | /** 15 | * Allow tiles using the TMS coordinate system (origin bottom left) to be used, 16 | * and displayed at their correct coordinates. 17 | */ 18 | flipY?: boolean; 19 | 20 | /** 21 | * The maximum native zoom level for this tile overlay i.e. the highest zoom level that the tile server provides. 22 | * Tiles are auto-scaled for higher zoom levels. 23 | */ 24 | maximumNativeZ?: number; 25 | 26 | /** 27 | * The maximum zoom level for this tile overlay. 28 | */ 29 | maximumZ?: number; 30 | 31 | /** 32 | * The minimum zoom level for this tile overlay. 33 | */ 34 | minimumZ?: number; 35 | 36 | /** 37 | * In offline-mode tiles are not fetched from the tile servers, rather only tiles stored in the cache directory are used. 38 | * Furthermore automated tile scaling is activated: if tile at a desired zoom level is not found from the cache directory, 39 | * then lower zoom level tile is used (up to 4 levels lower) and scaled. 40 | * 41 | * @default false 42 | */ 43 | offlineMode?: boolean; 44 | 45 | /** 46 | * Map layer opacity. Value between 0 - 1, with 0 meaning fully transparent. 47 | */ 48 | opacity?: number; 49 | 50 | /** 51 | * Defines maximum age in seconds for a cached tile before it's refreshed. 52 | * 53 | * NB! Refresh logic is "serve-stale-while-refresh" 54 | * i.e. to ensure map availability a stale (over max age) tile is served 55 | * while a tile refresh process is started in the background. 56 | */ 57 | tileCacheMaxAge?: number; 58 | 59 | /** 60 | * Enable caching of tiles in the specified directory. 61 | * Directory can be specified either as a normal path or in URL format (`file://`). 62 | * 63 | * Tiles are stored in tileCachePath directory as `/{z}/{x}/{y}` i.e. in sub-directories 2-levels deep, 64 | * filename is tile y-coordinate without any filetype-extension. 65 | * 66 | * NB! All cache management needs to be implemented by client e.g. deleting tiles to manage use of storage space etc. 67 | */ 68 | tileCachePath?: string; 69 | 70 | /** 71 | * Tile size, default size is 256 (for tiles of 256 _ 256 pixels). 72 | * High-res (aka 'retina') tiles are 512 (tiles of 512 _ 512 pixels) 73 | */ 74 | tileSize?: number; 75 | 76 | /** 77 | * The url template of the map tileserver. 78 | * (URLTile) The patterns {x} {y} {z} will be replaced at runtime. 79 | * For example, http://c.tile.openstreetmap.org/{z}/{x}/{y}.png. 80 | * 81 | * It is also possible to refer to tiles in local filesystem with file:///top-level-directory/sub-directory/{z}/{x}/{y}.png URL-format. 82 | * (WMSTile) The patterns {minX} {maxX} {minY} {maxY} {width} {height} will be replaced at runtime according to EPSG:900913 specification bounding box. 83 | * For example, https://demo.geo-solutions.it/geoserver/tiger/wms?service=WMS&version=1.1.0&request=GetMap&layers=tiger:poi&styles=&bbox={minX},{minY},{maxX},{maxY}&width={width}&height={height}&srs=EPSG:900913&format=image/png&transparent=true&format_options=dpi:213. 84 | */ 85 | 86 | urlTemplate: string; 87 | }; 88 | 89 | type NativeProps = MapUrlTileProps; 90 | 91 | class MapUrlTile extends React.Component { 92 | render() { 93 | return ; 94 | } 95 | } 96 | 97 | const OsmMapUrlTile = requireNativeComponent('OsmMapUrlTile'); 98 | 99 | export default MapUrlTile; 100 | -------------------------------------------------------------------------------- /src/MapView.types.ts: -------------------------------------------------------------------------------- 1 | import type { ClickEvent, LatLng, Point, Region } from './sharedTypes'; 2 | import type { NativeSyntheticEvent } from 'react-native'; 3 | 4 | // All types in this file are directly exported with the package for external 5 | // use. 6 | 7 | export type Camera = { 8 | center: LatLng; 9 | }; 10 | 11 | export type MapStyleElement = { 12 | featureType?: string; 13 | elementType?: string; 14 | stylers: object[]; 15 | }; 16 | 17 | export type EdgePadding = { 18 | top: Number; 19 | right: Number; 20 | bottom: Number; 21 | left: Number; 22 | }; 23 | 24 | export type MapType = 25 | | 'hybrid' 26 | | 'mutedStandard' 27 | | 'none' 28 | | 'satellite' 29 | | 'standard' 30 | | 'terrain'; 31 | 32 | export type MapTypes = { 33 | STANDARD: 'standard'; 34 | SATELLITE: 'satellite'; 35 | HYBRID: 'hybrid'; 36 | TERRAIN: 'terrain'; 37 | NONE: 'none'; 38 | MUTEDSTANDARD: 'mutedStandard'; 39 | }; 40 | 41 | export type IndoorLevel = { 42 | index: number; 43 | name: string; 44 | shortName: string; 45 | }; 46 | 47 | export type ActiveIndoorLevel = { 48 | activeLevelIndex: number; 49 | name: string; 50 | shortName: string; 51 | }; 52 | 53 | export type IndoorLevelActivatedEvent = NativeSyntheticEvent<{ 54 | IndoorLevel: ActiveIndoorLevel; 55 | }>; 56 | 57 | export type IndoorBuilding = { 58 | underground: boolean; 59 | activeLevelIndex: number; 60 | levels: IndoorLevel[]; 61 | }; 62 | 63 | export type IndoorBuildingEvent = NativeSyntheticEvent<{ 64 | IndoorBuilding: IndoorBuilding; 65 | }>; 66 | 67 | export type KmlMarker = { 68 | id: string; 69 | title: string; 70 | description: string; 71 | coordinate: LatLng; 72 | position: Point; 73 | }; 74 | 75 | export type KmlMapEvent = NativeSyntheticEvent<{ markers: KmlMarker[] }>; 76 | 77 | export type LongPressEvent = ClickEvent<{ 78 | /** 79 | * @platform Android 80 | */ 81 | action?: 'long-press'; 82 | }>; 83 | 84 | export type PanDragEvent = ClickEvent; 85 | 86 | export type PoiClickEvent = NativeSyntheticEvent<{ 87 | placeId: string; 88 | name: string; 89 | coordinate: LatLng; 90 | 91 | /** 92 | * @platform Android 93 | */ 94 | position?: Point; 95 | }>; 96 | 97 | export type MapPressEvent = ClickEvent<{ 98 | /** 99 | * @platform Android 100 | */ 101 | action?: 'press' | 'marker-press'; 102 | }>; 103 | 104 | export type Details = { 105 | isGesture?: boolean; 106 | }; 107 | 108 | export type UserLocationChangeEvent = NativeSyntheticEvent<{ 109 | coordinate?: LatLng & { 110 | altitude: number; 111 | timestamp: number; 112 | accuracy: number; 113 | speed: number; 114 | heading: number; 115 | 116 | /** 117 | * @platform iOS 118 | */ 119 | altitudeAccuracy?: number; 120 | 121 | /** 122 | * @platform Android 123 | */ 124 | isFromMockProvider?: boolean; 125 | }; 126 | 127 | /** 128 | * @platform iOS 129 | */ 130 | error?: { 131 | message: string; 132 | }; 133 | }>; 134 | 135 | export type ChangeEvent = NativeSyntheticEvent<{ 136 | continuous: boolean; 137 | region: Region; 138 | }>; 139 | 140 | export type FitToOptions = { 141 | edgePadding?: EdgePadding; 142 | animated?: boolean; 143 | }; 144 | 145 | export type BoundingBox = { northEast: LatLng; southWest: LatLng }; 146 | 147 | export type SnapshotOptions = { 148 | /** optional, when omitted the view-width is used */ 149 | width?: number; 150 | /** optional, when omitted the view-height is used */ 151 | height?: number; 152 | /** __iOS only__, optional region to render */ 153 | region?: Region; 154 | /** image formats, defaults to 'png' */ 155 | format?: 'png' | 'jpg'; 156 | /** image quality: 0..1 (only relevant for jpg, default: 1) */ 157 | quality?: number; 158 | /** result types, defaults to 'file' */ 159 | result?: 'file' | 'base64'; 160 | }; 161 | 162 | export type Address = { 163 | administrativeArea: string; 164 | country: string; 165 | countryCode: string; 166 | locality: string; 167 | name: string; 168 | postalCode: string; 169 | subAdministrativeArea: string; 170 | subLocality: string; 171 | thoroughfare: string; 172 | }; 173 | 174 | export type NativeCommandName = 175 | | 'animateCamera' 176 | | 'animateToRegion' 177 | | 'coordinateForPoint' 178 | | 'fitToCoordinates' 179 | | 'fitToElements' 180 | | 'fitToSuppliedMarkers' 181 | | 'getAddressFromCoordinates' 182 | | 'getCamera' 183 | | 'getMapBoundaries' 184 | | 'getMarkersFrames' 185 | | 'pointForCoordinate' 186 | | 'setCamera' 187 | | 'setIndoorActiveLevelIndex' 188 | | 'setMapBoundaries' 189 | | 'takeSnapshot'; 190 | -------------------------------------------------------------------------------- /src/MapViewNativeComponent.ts: -------------------------------------------------------------------------------- 1 | import type { HostComponent } from 'react-native'; 2 | import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; 3 | import type { NativeProps } from './MapView'; 4 | import type { Camera, EdgePadding } from './MapView.types'; 5 | import type { LatLng, Region } from './sharedTypes'; 6 | 7 | export type MapViewNativeComponentType = HostComponent; 8 | 9 | interface NativeCommands { 10 | animateToRegion: ( 11 | viewRef: NonNullable< 12 | React.RefObject['current'] 13 | >, 14 | region: Region, 15 | duration: number 16 | ) => void; 17 | 18 | setCamera: ( 19 | viewRef: NonNullable< 20 | React.RefObject['current'] 21 | >, 22 | camera: Partial 23 | ) => void; 24 | 25 | animateCamera: ( 26 | viewRef: NonNullable< 27 | React.RefObject['current'] 28 | >, 29 | camera: Partial, 30 | duration: number 31 | ) => void; 32 | 33 | fitToElements: ( 34 | viewRef: NonNullable< 35 | React.RefObject['current'] 36 | >, 37 | edgePadding: EdgePadding, 38 | animated: boolean 39 | ) => void; 40 | 41 | fitToSuppliedMarkers: ( 42 | viewRef: NonNullable< 43 | React.RefObject['current'] 44 | >, 45 | markers: string[], 46 | edgePadding: EdgePadding, 47 | animated: boolean 48 | ) => void; 49 | 50 | fitToCoordinates: ( 51 | viewRef: NonNullable< 52 | React.RefObject['current'] 53 | >, 54 | coordinates: LatLng[], 55 | edgePadding: EdgePadding, 56 | animated: boolean 57 | ) => void; 58 | 59 | setMapBoundaries: ( 60 | viewRef: NonNullable< 61 | React.RefObject['current'] 62 | >, 63 | northEast: LatLng, 64 | southWest: LatLng 65 | ) => void; 66 | 67 | setIndoorActiveLevelIndex: ( 68 | viewRef: NonNullable< 69 | React.RefObject['current'] 70 | >, 71 | activeLevelIndex: number 72 | ) => void; 73 | } 74 | 75 | export const Commands: NativeCommands = codegenNativeCommands({ 76 | supportedCommands: [ 77 | 'animateToRegion', 78 | 'setCamera', 79 | 'animateCamera', 80 | 'fitToElements', 81 | 'fitToSuppliedMarkers', 82 | 'fitToCoordinates', 83 | 'setMapBoundaries', 84 | 'setIndoorActiveLevelIndex', 85 | ], 86 | }); 87 | -------------------------------------------------------------------------------- /src/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | it.todo('write a test'); 2 | -------------------------------------------------------------------------------- /src/decorateMapComponent.ts: -------------------------------------------------------------------------------- 1 | import type { HostComponent } from 'react-native'; 2 | 3 | export const createNotSupportedComponent = (message: string) => () => { 4 | console.error(message); 5 | return null; 6 | }; 7 | 8 | export type NativeComponent = 9 | | HostComponent 10 | | ReturnType; 11 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import MapView, { MapViewProps } from './MapView'; 2 | export type { MapViewProps }; 3 | import Marker from './MapMarker'; 4 | import Polyline from './MapPolyline'; 5 | import Polygon from './MapPolygon'; 6 | export type { MapPolylineProps, PolylinePressEvent } from './MapPolyline'; 7 | export type { MapPolygonProps } from './MapPolygon'; 8 | export { default as Callout } from './MapCallout'; 9 | export type { MapCalloutProps } from './MapCallout'; 10 | export { default as Circle } from './MapCircle'; 11 | export type { MapCircleProps } from './MapCircle'; 12 | export { default as UrlTile } from './MapUrlTile'; 13 | export type { MapUrlTileProps } from './MapUrlTile'; 14 | export * from './MapView.types'; 15 | export * from './sharedTypes'; 16 | export default MapView; 17 | export { Marker, Polyline, Polygon }; 18 | export { default as AnimatedRegion } from './AnimatedRegion'; 19 | -------------------------------------------------------------------------------- /src/sharedTypes.ts: -------------------------------------------------------------------------------- 1 | import type { NativeSyntheticEvent } from 'react-native'; 2 | 3 | export type Provider = 'google' | undefined; 4 | 5 | export type LatLng = { 6 | latitude: number; 7 | longitude: number; 8 | }; 9 | 10 | export type Point = { 11 | x: number; 12 | y: number; 13 | }; 14 | 15 | export type Region = LatLng & { 16 | latitudeDelta: number; 17 | longitudeDelta: number; 18 | }; 19 | 20 | export type Frame = Point & { height: number; width: number }; 21 | 22 | export type CalloutPressEvent = NativeSyntheticEvent<{ 23 | action: 'callout-press'; 24 | 25 | /** 26 | * @platform iOS 27 | */ 28 | frame?: Frame; 29 | 30 | /** 31 | * @platform iOS 32 | */ 33 | id?: string; 34 | 35 | /** 36 | * @platform iOS 37 | */ 38 | point?: Point; 39 | 40 | /** 41 | * @platform Android 42 | */ 43 | coordinate?: LatLng; 44 | 45 | /** 46 | * @platform Android 47 | */ 48 | position?: Point; 49 | }>; 50 | 51 | export type LineCapType = 'butt' | 'round' | 'square'; 52 | export type LineJoinType = 'miter' | 'round' | 'bevel'; 53 | 54 | export type ClickEvent = NativeSyntheticEvent< 55 | { coordinate: LatLng; position: Point } & T 56 | >; 57 | 58 | export type MarkerDeselectEvent = Omit< 59 | ClickEvent<{ 60 | action: 'marker-deselect'; 61 | id: string; 62 | }>, 63 | 'position' 64 | >; 65 | 66 | export type MarkerSelectEvent = Omit< 67 | ClickEvent<{ id: string; action: 'marker-select' }>, 68 | 'position' 69 | >; 70 | 71 | export type MarkerDragEvent = ClickEvent<{ 72 | /** 73 | * @platform iOS 74 | */ 75 | id?: string; 76 | }>; 77 | 78 | export type MarkerDragStartEndEvent = NativeSyntheticEvent<{ 79 | coordinate: LatLng; 80 | 81 | /** 82 | * @platform iOS 83 | */ 84 | id?: string; 85 | 86 | /** 87 | * @platform Android 88 | */ 89 | position?: Point; 90 | }>; 91 | 92 | export type MarkerPressEvent = NativeSyntheticEvent<{ 93 | id: string; 94 | action: 'marker-press'; 95 | coordinate: LatLng; 96 | 97 | /** 98 | * @platform Android 99 | */ 100 | position?: Point; 101 | }>; 102 | -------------------------------------------------------------------------------- /src/sharedTypesInternal.ts: -------------------------------------------------------------------------------- 1 | export type Modify = Omit & R; 2 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "./tsconfig", 4 | "exclude": ["example"] 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@splicer97/react-native-osmdroid": ["./src/index"] 6 | }, 7 | "allowUnreachableCode": false, 8 | "allowUnusedLabels": false, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "jsx": "react", 12 | "lib": ["esnext"], 13 | "module": "esnext", 14 | "moduleResolution": "node", 15 | "noFallthroughCasesInSwitch": true, 16 | "noImplicitReturns": true, 17 | "noImplicitUseStrict": false, 18 | "noStrictGenericChecks": false, 19 | "noUncheckedIndexedAccess": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "resolveJsonModule": true, 23 | "skipLibCheck": true, 24 | "strict": true, 25 | "target": "esnext" 26 | } 27 | } 28 | --------------------------------------------------------------------------------