├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md ├── funding-octocat.svg ├── stale.yml └── workflows │ └── verify.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode ├── c_cpp_properties.json └── settings.json ├── CODEOWNERS ├── LICENSE ├── NuGet.config ├── README.md ├── RNPermissions.podspec ├── android ├── build.gradle └── src │ ├── main │ ├── AndroidManifest.xml │ ├── AndroidManifestNew.xml │ └── java │ │ └── com │ │ └── zoontek │ │ └── rnpermissions │ │ ├── RNPermissionsModuleImpl.kt │ │ └── RNPermissionsPackage.kt │ ├── newarch │ └── com │ │ └── zoontek │ │ └── rnpermissions │ │ └── RNPermissionsModule.kt │ └── oldarch │ └── com │ └── zoontek │ └── rnpermissions │ └── RNPermissionsModule.kt ├── app.plugin.js ├── docs ├── location_always_first_prompt.png ├── location_always_second_prompt.png └── location_always_upgrade.png ├── example ├── .bundle │ └── config ├── .yarnrc ├── Gemfile ├── Gemfile.lock ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ └── fonts │ │ │ │ └── MaterialCommunityIcons.ttf │ │ │ ├── java │ │ │ └── com │ │ │ │ └── rnpermissionsexample │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainApplication.kt │ │ │ └── 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 │ ├── Podfile │ ├── Podfile.lock │ ├── RNPermissionsExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── RNPermissionsExample.xcscheme │ ├── RNPermissionsExample.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── RNPermissionsExample │ │ ├── AppDelegate.swift │ │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── PrivacyInfo.xcprivacy ├── metro.config.js ├── package.json ├── src │ └── App.tsx ├── tsconfig.json ├── windows │ ├── .gitignore │ ├── Example.sln │ └── Example │ │ ├── .gitignore │ │ ├── App.cpp │ │ ├── App.h │ │ ├── App.idl │ │ ├── App.xaml │ │ ├── Assets │ │ ├── LockScreenLogo.scale-200.png │ │ ├── SplashScreen.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ │ ├── StoreLogo.png │ │ └── Wide310x150Logo.scale-200.png │ │ ├── AutolinkedNativeModules.g.cpp │ │ ├── AutolinkedNativeModules.g.h │ │ ├── Example.vcxproj │ │ ├── Example.vcxproj.filters │ │ ├── Example_TemporaryKey.pfx │ │ ├── Package.appxmanifest │ │ ├── PropertySheet.props │ │ ├── ReactPackageProvider.cpp │ │ ├── ReactPackageProvider.h │ │ ├── packages.config │ │ ├── pch.cpp │ │ └── pch.h └── yarn.lock ├── fetchWindowsCapabilites.js ├── ios ├── AppTrackingTransparency │ ├── RNPermissionHandlerAppTrackingTransparency.h │ └── RNPermissionHandlerAppTrackingTransparency.mm ├── Bluetooth │ ├── RNPermissionHandlerBluetooth.h │ └── RNPermissionHandlerBluetooth.mm ├── Calendars │ ├── RNPermissionHandlerCalendars.h │ └── RNPermissionHandlerCalendars.mm ├── CalendarsWriteOnly │ ├── RNPermissionHandlerCalendarsWriteOnly.h │ └── RNPermissionHandlerCalendarsWriteOnly.mm ├── Camera │ ├── RNPermissionHandlerCamera.h │ └── RNPermissionHandlerCamera.mm ├── Contacts │ ├── RNPermissionHandlerContacts.h │ └── RNPermissionHandlerContacts.mm ├── FaceID │ ├── RNPermissionHandlerFaceID.h │ └── RNPermissionHandlerFaceID.mm ├── LocationAccuracy │ ├── RNPermissionHandlerLocationAccuracy.h │ └── RNPermissionHandlerLocationAccuracy.mm ├── LocationAlways │ ├── RNPermissionHandlerLocationAlways.h │ └── RNPermissionHandlerLocationAlways.mm ├── LocationWhenInUse │ ├── RNPermissionHandlerLocationWhenInUse.h │ └── RNPermissionHandlerLocationWhenInUse.mm ├── MediaLibrary │ ├── RNPermissionHandlerMediaLibrary.h │ └── RNPermissionHandlerMediaLibrary.mm ├── Microphone │ ├── RNPermissionHandlerMicrophone.h │ └── RNPermissionHandlerMicrophone.mm ├── Motion │ ├── RNPermissionHandlerMotion.h │ └── RNPermissionHandlerMotion.mm ├── Notifications │ ├── RNPermissionHandlerNotifications.h │ └── RNPermissionHandlerNotifications.mm ├── PhotoLibrary │ ├── RNPermissionHandlerPhotoLibrary.h │ └── RNPermissionHandlerPhotoLibrary.mm ├── PhotoLibraryAddOnly │ ├── RNPermissionHandlerPhotoLibraryAddOnly.h │ └── RNPermissionHandlerPhotoLibraryAddOnly.mm ├── PrivacyInfo.xcprivacy ├── RNPermissions.h ├── RNPermissions.mm ├── RNPermissions.xcodeproj │ └── project.pbxproj ├── Reminders │ ├── RNPermissionHandlerReminders.h │ └── RNPermissionHandlerReminders.mm ├── Siri │ ├── RNPermissionHandlerSiri.h │ └── RNPermissionHandlerSiri.mm ├── SpeechRecognition │ ├── RNPermissionHandlerSpeechRecognition.h │ └── RNPermissionHandlerSpeechRecognition.mm └── StoreKit │ ├── RNPermissionHandlerStoreKit.h │ └── RNPermissionHandlerStoreKit.mm ├── mock.js ├── package.json ├── scripts └── setup.rb ├── src ├── NativeRNPermissions.ts ├── contract.ts ├── expo.ts ├── index.ts ├── methods.android.ts ├── methods.ios.ts ├── methods.ts ├── methods.windows.ts ├── permissions.android.ts ├── permissions.ios.ts ├── permissions.ts ├── permissions.windows.ts ├── results.ts ├── types.ts ├── unsupportedMethods.ts └── utils.ts ├── tsconfig.json ├── windows ├── .gitignore ├── ExperimentalFeatures.props ├── RNPermissions.sln └── RNPermissions │ ├── PropertySheet.props │ ├── RNPermissions.cpp │ ├── RNPermissions.def │ ├── RNPermissions.h │ ├── RNPermissions.rc │ ├── RNPermissions.vcxproj │ ├── RNPermissions.vcxproj.filters │ ├── ReactPackageProvider.cpp │ ├── ReactPackageProvider.h │ ├── ReactPackageProvider.idl │ ├── codegen │ ├── .clang-format │ ├── NativeRNPermissionsDataTypes.g.h │ └── NativeRNPermissionsSpec.g.h │ ├── packages.config │ ├── packages.lock.json │ ├── pch.cpp │ ├── pch.h │ ├── resource.h │ └── targetver.h └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_size = 2 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.bat] 11 | end_of_line = crlf 12 | 13 | [*.{gradle,xml}] 14 | indent_size = 4 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .eslintrc.js 2 | 3 | dist/ 4 | node_modules 5 | example/ 6 | scripts/ 7 | 8 | app.plugin.js 9 | fetchWindowsCapabilites.js 10 | mock.js 11 | react-native.config.js 12 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | root: true, 5 | 6 | parser: '@typescript-eslint/parser', 7 | plugins: ['@typescript-eslint', 'react', 'react-hooks'], 8 | 9 | env: { 10 | es6: true, 11 | }, 12 | 13 | parserOptions: { 14 | project: './tsconfig.json', 15 | ecmaFeatures: {jsx: true}, 16 | ecmaVersion: 2018, 17 | sourceType: 'module', 18 | }, 19 | 20 | settings: { 21 | react: {version: 'detect'}, 22 | }, 23 | 24 | globals: { 25 | __DEV__: true, 26 | __dirname: false, 27 | __fbBatchedBridgeConfig: false, 28 | alert: false, 29 | cancelAnimationFrame: false, 30 | cancelIdleCallback: false, 31 | clearImmediate: true, 32 | clearInterval: false, 33 | clearTimeout: false, 34 | console: false, 35 | document: false, 36 | ErrorUtils: false, 37 | escape: false, 38 | Event: false, 39 | EventTarget: false, 40 | exports: false, 41 | fetch: false, 42 | FormData: false, 43 | global: false, 44 | Headers: false, 45 | Intl: false, 46 | Map: true, 47 | module: false, 48 | navigator: false, 49 | process: false, 50 | Promise: true, 51 | requestAnimationFrame: true, 52 | requestIdleCallback: true, 53 | require: false, 54 | Set: true, 55 | setImmediate: true, 56 | setInterval: false, 57 | setTimeout: false, 58 | URL: false, 59 | URLSearchParams: false, 60 | WebSocket: true, 61 | window: false, 62 | XMLHttpRequest: false, 63 | }, 64 | 65 | rules: { 66 | // https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin 67 | '@typescript-eslint/ban-ts-comment': 'off', 68 | '@typescript-eslint/ban-ts-ignore': 'off', 69 | '@typescript-eslint/ban-types': 'off', 70 | '@typescript-eslint/camelcase': 'off', 71 | '@typescript-eslint/explicit-module-boundary-types': 'off', 72 | '@typescript-eslint/no-empty-function': 'off', 73 | '@typescript-eslint/no-explicit-any': 'off', 74 | '@typescript-eslint/no-use-before-define': 'off', 75 | '@typescript-eslint/no-var-requires': 'off', 76 | 77 | '@typescript-eslint/no-unused-vars': [ 78 | 'error', 79 | {argsIgnorePattern: '^_', ignoreRestSiblings: true}, 80 | ], 81 | 82 | // https://github.com/yannickcr/eslint-plugin-react 83 | 'react/display-name': 'off', 84 | 'react/prop-types': 'off', 85 | 86 | // https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks 87 | 'react-hooks/rules-of-hooks': 'error', 88 | 'react-hooks/exhaustive-deps': 'error', 89 | }, 90 | }; 91 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at zoontek@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [zoontek] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug report 2 | description: Report a reproducible bug or regression in this library. 3 | labels: [bug] 4 | assignees: 5 | - zoontek 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | # Bug report 11 | 12 | 👋 Hi! 13 | 14 | **🚨 Please fill the following carefully before opening a new issue 🚨** 15 | *(Your issue may be closed if it doesn't provide the required pieces of information)* 16 | - type: checkboxes 17 | attributes: 18 | label: Before submitting a new issue 19 | description: Please perform simple checks first. 20 | options: 21 | - label: I tested using the latest version of the library, as the bug might be already fixed. 22 | required: true 23 | - label: I tested using a [supported version](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md) of react native. 24 | required: true 25 | - label: I checked for possible duplicate issues, with possible answers. 26 | required: true 27 | - type: textarea 28 | id: summary 29 | attributes: 30 | label: Bug summary 31 | description: | 32 | Provide a clear and concise description of what the bug is. 33 | If needed, you can also provide other samples: error messages / stack traces, screenshots, gifs, etc. 34 | validations: 35 | required: true 36 | - type: input 37 | id: library-version 38 | attributes: 39 | label: Library version 40 | description: What version of the library are you using? 41 | placeholder: 'x.x.x' 42 | validations: 43 | required: true 44 | - type: textarea 45 | id: react-native-info 46 | attributes: 47 | label: Environment info 48 | description: Run `react-native info` in your terminal and paste the results here. 49 | render: shell 50 | validations: 51 | required: true 52 | - type: textarea 53 | id: steps-to-reproduce 54 | attributes: 55 | label: Steps to reproduce 56 | description: | 57 | - You must provide a clear list of steps and code to reproduce the problem. 58 | - Keep the code reproducing the bug as simple as possible, with the minimum amount of code required to reproduce the issue. See https://stackoverflow.com/help/mcve. 59 | - Is the issue happening on iOS, Android or both? 60 | - Do you run your app on a simulator (which OS version?) or on a physical device (which one? which OS version?) 61 | - If this library has additional install steps, describe them (e.g., pod install? jetify? etc). 62 | - Either re-create the bug using the repository's example app or link to a GitHub repository with code that reproduces the bug. 63 | - Explain the steps we need to take to reproduce the issue: 64 | value: | 65 | 1. … 66 | 2. … 67 | validations: 68 | required: true 69 | - type: textarea 70 | id: reproducible-sample-code 71 | attributes: 72 | label: Reproducible sample code 73 | description: Please add minimal runnable repro as explained above so that the bug can be tested in isolation. 74 | render: js 75 | validations: 76 | required: true 77 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: ➡ Expo issues 4 | url: https://github.com/expo/expo/issues 5 | about: If your issue is specific to usage with Expo, please open it on their repository. 6 | - name: ❓ Stack Overflow 7 | url: https://stackoverflow.com 8 | about: If this library works as promised but you need help, please ask questions there. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 💡 Feature request 2 | description: Submit your idea for a change in the codebase. 3 | labels: [feature request] 4 | assignees: 5 | - zoontek 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | # Feature request 11 | 12 | This issue should serve for you to present or pitch an idea to the maintainers - but remember that it would be better if you were to submit a PR instead 🤗 13 | - type: textarea 14 | id: why-is-this-needed 15 | attributes: 16 | label: Why it is needed? 17 | description: Please tell us a bit more of why you want this feature to be added, what's its origin. 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: possible-implementation 22 | attributes: 23 | label: Possible implementation 24 | description: It really helps if you could describe from a technical POV how this new feature would work, which code it rely on, etc. 25 | validations: 26 | required: false 27 | - type: textarea 28 | id: code-sample 29 | attributes: 30 | label: Code sample 31 | description: Please show how the new code could work, if doable. 32 | render: js 33 | validations: 34 | required: false 35 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Summary 4 | 5 | 13 | 14 | ## Test Plan 15 | 16 | 17 | 18 | ### What's required for testing (prerequisites)? 19 | 20 | ### What are the steps to test it (after prerequisites)? 21 | 22 | ## Compatibility 23 | 24 | | OS | Implemented | 25 | | ------- | :---------: | 26 | | iOS | ✅❌ | 27 | | Android | ✅❌ | 28 | 29 | ## Checklist 30 | 31 | 32 | 33 | - [ ] I have tested this on a device and a simulator 34 | - [ ] I added the documentation in `README.md` 35 | - [ ] I added a sample use of the API in the example project (`example/App.tsx`) 36 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale based on: https://github.com/facebook/react-native/blob/master/.github/stale.yml 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 5 | 60 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | daysUntilClose: 8 | 7 9 | # Issues or Pull Requests. 10 | exemptLabels: 11 | - pinned 12 | - security 13 | - discussion 14 | 15 | # Set to true to ignore issues in a project (defaults to false) 16 | exemptProjects: 17 | false 18 | # Set to true to ignore issues in a milestone (defaults to false) 19 | exemptMilestones: 20 | false 21 | # Set to true to ignore issues with an assignee (defaults to false) 22 | exemptAssignees: 23 | false 24 | # Label to use when marking as stale 25 | staleLabel: 26 | stale 27 | # Comment to post when marking as stale. Set to `false` to disable 28 | markComment: > 29 | This issue has been automatically marked as stale because it has not had 30 | recent activity. It will be closed if no further activity occurs. Thank you 31 | for your contributions. You may also mark this issue as a "discussion" and I 32 | will leave this open. 33 | # Comment to post when closing a stale Issue or Pull Request. 34 | closeComment: > 35 | Closing this issue after a prolonged period of inactivity. Fell free to reopen 36 | this issue, if this still affecting you. 37 | # Limit the number of actions per hour, from 1-30. Default is 30 38 | limitPerRun: 39 | 30 40 | # Limit to only `issues` or `pulls` 41 | only: issues 42 | -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | prepack: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: lts/* 19 | 20 | - run: yarn install --frozen-lockfile 21 | - run: yarn prepack 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # Bundle artifact 45 | *.jsbundle 46 | 47 | # Bob 48 | dist/ 49 | 50 | # Ruby / CocoaPods 51 | **/Pods/ 52 | **/vendor/bundle/ 53 | 54 | # Temporary files created by Metro to check the health of the file watcher 55 | .metro-health-check* 56 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | Pods/ 4 | 5 | example/android/app/build/ 6 | example/ios/build/ 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "printWidth": 100, 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "plugins": ["prettier-plugin-organize-imports"] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": ["${workspaceFolder}/**"], 6 | "defines": ["_DEBUG", "UNICODE", "_UNICODE"], 7 | "windowsSdkVersion": "10.0.22621.0", 8 | "compilerPath": "cl.exe", 9 | "cStandard": "c17", 10 | "cppStandard": "c++17", 11 | "intelliSenseMode": "windows-msvc-x64" 12 | } 13 | ], 14 | "version": 4 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "algorithm": "cpp", 4 | "array": "cpp", 5 | "atomic": "cpp", 6 | "bit": "cpp", 7 | "bitset": "cpp", 8 | "cctype": "cpp", 9 | "cfenv": "cpp", 10 | "charconv": "cpp", 11 | "chrono": "cpp", 12 | "cinttypes": "cpp", 13 | "clocale": "cpp", 14 | "cmath": "cpp", 15 | "compare": "cpp", 16 | "concepts": "cpp", 17 | "condition_variable": "cpp", 18 | "coroutine": "cpp", 19 | "csetjmp": "cpp", 20 | "csignal": "cpp", 21 | "cstdarg": "cpp", 22 | "cstddef": "cpp", 23 | "cstdint": "cpp", 24 | "cstdio": "cpp", 25 | "cstdlib": "cpp", 26 | "cstring": "cpp", 27 | "ctime": "cpp", 28 | "cwchar": "cpp", 29 | "deque": "cpp", 30 | "exception": "cpp", 31 | "filesystem": "cpp", 32 | "format": "cpp", 33 | "forward_list": "cpp", 34 | "fstream": "cpp", 35 | "functional": "cpp", 36 | "future": "cpp", 37 | "initializer_list": "cpp", 38 | "iomanip": "cpp", 39 | "ios": "cpp", 40 | "iosfwd": "cpp", 41 | "iostream": "cpp", 42 | "istream": "cpp", 43 | "iterator": "cpp", 44 | "limits": "cpp", 45 | "list": "cpp", 46 | "locale": "cpp", 47 | "map": "cpp", 48 | "memory": "cpp", 49 | "memory_resource": "cpp", 50 | "mutex": "cpp", 51 | "new": "cpp", 52 | "optional": "cpp", 53 | "ostream": "cpp", 54 | "queue": "cpp", 55 | "random": "cpp", 56 | "ranges": "cpp", 57 | "ratio": "cpp", 58 | "regex": "cpp", 59 | "semaphore": "cpp", 60 | "set": "cpp", 61 | "shared_mutex": "cpp", 62 | "source_location": "cpp", 63 | "span": "cpp", 64 | "sstream": "cpp", 65 | "stack": "cpp", 66 | "stdexcept": "cpp", 67 | "stop_token": "cpp", 68 | "streambuf": "cpp", 69 | "string": "cpp", 70 | "system_error": "cpp", 71 | "thread": "cpp", 72 | "tuple": "cpp", 73 | "type_traits": "cpp", 74 | "typeinfo": "cpp", 75 | "unordered_map": "cpp", 76 | "unordered_set": "cpp", 77 | "utility": "cpp", 78 | "variant": "cpp", 79 | "vector": "cpp", 80 | "xfacet": "cpp", 81 | "xhash": "cpp", 82 | "xiosbase": "cpp", 83 | "xlocale": "cpp", 84 | "xlocbuf": "cpp", 85 | "xlocinfo": "cpp", 86 | "xlocmes": "cpp", 87 | "xlocmon": "cpp", 88 | "xlocnum": "cpp", 89 | "xloctime": "cpp", 90 | "xmemory": "cpp", 91 | "xstring": "cpp", 92 | "xtr1common": "cpp", 93 | "xtree": "cpp", 94 | "xutility": "cpp" 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global owners 2 | * @zoontek 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mathieu Acthernoene 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /RNPermissions.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "RNPermissions" 7 | 8 | s.version = package["version"] 9 | s.license = package["license"] 10 | s.summary = package["description"] 11 | s.author = package["author"] 12 | s.homepage = package["homepage"] 13 | 14 | s.platforms = { :ios => "12.4", :tvos => "12.4" } 15 | s.requires_arc = true 16 | 17 | s.source = { :git => package["repository"]["url"], :tag => s.version } 18 | s.resource_bundles = { 'RNPermissionsPrivacyInfo' => 'ios/PrivacyInfo.xcprivacy' } 19 | 20 | s.source_files = "ios/*.{h,mm}" 21 | # s.frameworks = 22 | 23 | if ENV['RCT_NEW_ARCH_ENABLED'] == "1" then 24 | install_modules_dependencies(s) 25 | else 26 | s.dependency "React-Core" 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.safeExtGet = {prop, fallback -> 3 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 4 | } 5 | repositories { 6 | google() 7 | gradlePluginPortal() 8 | } 9 | dependencies { 10 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet("kotlinVersion", "1.8.0")}") 11 | classpath("com.android.tools.build:gradle:8.1.1") 12 | } 13 | } 14 | 15 | def isNewArchitectureEnabled() { 16 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" 17 | } 18 | 19 | apply plugin: "com.android.library" 20 | apply plugin: "kotlin-android" 21 | 22 | if (isNewArchitectureEnabled()) { 23 | apply plugin: "com.facebook.react" 24 | } 25 | 26 | android { 27 | buildToolsVersion safeExtGet("buildToolsVersion", "34.0.0") 28 | compileSdkVersion safeExtGet("compileSdkVersion", 34) 29 | 30 | if (project.android.hasProperty("namespace")) { 31 | namespace "com.zoontek.rnpermissions" 32 | 33 | buildFeatures { 34 | buildConfig true 35 | } 36 | sourceSets { 37 | main { 38 | manifest.srcFile "src/main/AndroidManifestNew.xml" 39 | } 40 | } 41 | } 42 | defaultConfig { 43 | buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()) 44 | minSdkVersion safeExtGet("minSdkVersion", 23) 45 | targetSdkVersion safeExtGet("targetSdkVersion", 34) 46 | } 47 | lintOptions { 48 | abortOnError false 49 | } 50 | sourceSets { 51 | main { 52 | if (isNewArchitectureEnabled()) { 53 | java.srcDirs += ["src/newarch"] 54 | } else { 55 | java.srcDirs += ["src/oldarch"] 56 | } 57 | } 58 | } 59 | } 60 | 61 | repositories { 62 | maven { 63 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 64 | url("$rootDir/../node_modules/react-native/android") 65 | } 66 | mavenCentral() 67 | google() 68 | } 69 | 70 | dependencies { 71 | //noinspection GradleDynamicVersion 72 | implementation "com.facebook.react:react-native:+" // From node_modules 73 | } 74 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifestNew.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/zoontek/rnpermissions/RNPermissionsPackage.kt: -------------------------------------------------------------------------------- 1 | package com.zoontek.rnpermissions 2 | 3 | import com.facebook.react.TurboReactPackage 4 | import com.facebook.react.bridge.NativeModule 5 | import com.facebook.react.bridge.ReactApplicationContext 6 | import com.facebook.react.module.model.ReactModuleInfo 7 | import com.facebook.react.module.model.ReactModuleInfoProvider 8 | 9 | class RNPermissionsPackage : TurboReactPackage() { 10 | override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { 11 | return when (name) { 12 | RNPermissionsModuleImpl.NAME -> RNPermissionsModule(reactContext) 13 | else -> null 14 | } 15 | } 16 | 17 | override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { 18 | return ReactModuleInfoProvider { 19 | val moduleInfos: MutableMap = HashMap() 20 | val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 21 | 22 | val moduleInfo = ReactModuleInfo( 23 | RNPermissionsModuleImpl.NAME, 24 | RNPermissionsModuleImpl.NAME, 25 | false, 26 | false, 27 | true, 28 | false, 29 | isTurboModule 30 | ) 31 | 32 | moduleInfos[RNPermissionsModuleImpl.NAME] = moduleInfo 33 | moduleInfos 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/src/newarch/com/zoontek/rnpermissions/RNPermissionsModule.kt: -------------------------------------------------------------------------------- 1 | package com.zoontek.rnpermissions 2 | 3 | import android.util.SparseArray 4 | 5 | import com.facebook.react.bridge.Callback 6 | import com.facebook.react.bridge.Promise 7 | import com.facebook.react.bridge.ReactApplicationContext 8 | import com.facebook.react.bridge.ReadableArray 9 | import com.facebook.react.module.annotations.ReactModule 10 | import com.facebook.react.modules.core.PermissionListener 11 | 12 | @ReactModule(name = RNPermissionsModuleImpl.NAME) 13 | class RNPermissionsModule(reactContext: ReactApplicationContext?) : 14 | NativeRNPermissionsSpec(reactContext), PermissionListener { 15 | 16 | private val callbacks = SparseArray() 17 | 18 | override fun getName(): String { 19 | return RNPermissionsModuleImpl.NAME 20 | } 21 | 22 | override fun openSettings(type: String?, promise: Promise) { 23 | RNPermissionsModuleImpl.openSettings(reactApplicationContext, type, promise) 24 | } 25 | 26 | override fun canScheduleExactAlarms(promise: Promise) { 27 | RNPermissionsModuleImpl.canScheduleExactAlarms(reactApplicationContext, promise) 28 | } 29 | 30 | override fun canUseFullScreenIntent(promise: Promise) { 31 | RNPermissionsModuleImpl.canUseFullScreenIntent(reactApplicationContext, promise) 32 | } 33 | 34 | override fun check(permission: String, promise: Promise) { 35 | RNPermissionsModuleImpl.check(reactApplicationContext, permission, promise) 36 | } 37 | 38 | override fun checkNotifications(promise: Promise) { 39 | RNPermissionsModuleImpl.checkNotifications(reactApplicationContext, promise) 40 | } 41 | 42 | override fun checkMultiple(permissions: ReadableArray, promise: Promise) { 43 | RNPermissionsModuleImpl.checkMultiple(reactApplicationContext, permissions, promise) 44 | } 45 | 46 | override fun request(permission: String, promise: Promise) { 47 | RNPermissionsModuleImpl.request(reactApplicationContext, this, callbacks, permission, promise) 48 | } 49 | 50 | override fun requestNotifications(options: ReadableArray, promise: Promise) { 51 | RNPermissionsModuleImpl.requestNotifications(reactApplicationContext, promise) 52 | } 53 | 54 | override fun requestMultiple(permissions: ReadableArray, promise: Promise) { 55 | RNPermissionsModuleImpl.requestMultiple(reactApplicationContext, this, callbacks, permissions, promise) 56 | } 57 | 58 | override fun shouldShowRequestRationale(permission: String, promise: Promise) { 59 | RNPermissionsModuleImpl.shouldShowRequestRationale(reactApplicationContext, permission, promise) 60 | } 61 | 62 | override fun checkLocationAccuracy(promise: Promise) { 63 | RNPermissionsModuleImpl.checkLocationAccuracy(promise) 64 | } 65 | 66 | override fun requestLocationAccuracy(purposeKey: String, promise: Promise) { 67 | RNPermissionsModuleImpl.requestLocationAccuracy(promise) 68 | } 69 | 70 | override fun openPhotoPicker(promise: Promise) { 71 | RNPermissionsModuleImpl.openPhotoPicker(promise) 72 | } 73 | 74 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray): Boolean { 75 | return RNPermissionsModuleImpl.onRequestPermissionsResult(reactApplicationContext, callbacks, requestCode, grantResults) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /android/src/oldarch/com/zoontek/rnpermissions/RNPermissionsModule.kt: -------------------------------------------------------------------------------- 1 | package com.zoontek.rnpermissions 2 | 3 | import android.util.SparseArray 4 | 5 | import com.facebook.react.bridge.Callback 6 | import com.facebook.react.bridge.Promise 7 | import com.facebook.react.bridge.ReactApplicationContext 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule 9 | import com.facebook.react.bridge.ReactMethod 10 | import com.facebook.react.bridge.ReadableArray 11 | import com.facebook.react.module.annotations.ReactModule 12 | import com.facebook.react.modules.core.PermissionListener 13 | 14 | @ReactModule(name = RNPermissionsModuleImpl.NAME) 15 | class RNPermissionsModule(reactContext: ReactApplicationContext?) : 16 | ReactContextBaseJavaModule(reactContext), PermissionListener { 17 | 18 | private val callbacks = SparseArray() 19 | 20 | override fun getName(): String { 21 | return RNPermissionsModuleImpl.NAME 22 | } 23 | 24 | @ReactMethod 25 | fun openSettings(type: String?, promise: Promise) { 26 | RNPermissionsModuleImpl.openSettings(reactApplicationContext, type, promise) 27 | } 28 | 29 | @ReactMethod 30 | fun canScheduleExactAlarms(promise: Promise) { 31 | RNPermissionsModuleImpl.canScheduleExactAlarms(reactApplicationContext, promise) 32 | } 33 | 34 | @ReactMethod 35 | fun canUseFullScreenIntent(promise: Promise) { 36 | RNPermissionsModuleImpl.canUseFullScreenIntent(reactApplicationContext, promise) 37 | } 38 | 39 | @ReactMethod 40 | fun check(permission: String, promise: Promise) { 41 | RNPermissionsModuleImpl.check(reactApplicationContext, permission, promise) 42 | } 43 | 44 | @ReactMethod 45 | fun checkNotifications(promise: Promise) { 46 | RNPermissionsModuleImpl.checkNotifications(reactApplicationContext, promise) 47 | } 48 | 49 | @ReactMethod 50 | fun checkMultiple(permissions: ReadableArray, promise: Promise) { 51 | RNPermissionsModuleImpl.checkMultiple(reactApplicationContext, permissions, promise) 52 | } 53 | 54 | @ReactMethod 55 | fun request(permission: String, promise: Promise) { 56 | RNPermissionsModuleImpl.request(reactApplicationContext, this, callbacks, permission, promise) 57 | } 58 | 59 | @ReactMethod 60 | fun requestNotifications(options: ReadableArray, promise: Promise) { 61 | RNPermissionsModuleImpl.requestNotifications(reactApplicationContext, promise) 62 | } 63 | 64 | @ReactMethod 65 | fun requestMultiple(permissions: ReadableArray, promise: Promise) { 66 | RNPermissionsModuleImpl.requestMultiple(reactApplicationContext, this, callbacks, permissions, promise) 67 | } 68 | 69 | @ReactMethod 70 | fun shouldShowRequestRationale(permission: String, promise: Promise) { 71 | RNPermissionsModuleImpl.shouldShowRequestRationale(reactApplicationContext, permission, promise) 72 | } 73 | 74 | @ReactMethod 75 | fun checkLocationAccuracy(promise: Promise) { 76 | RNPermissionsModuleImpl.checkLocationAccuracy(promise) 77 | } 78 | 79 | @ReactMethod 80 | fun requestLocationAccuracy(purposeKey: String, promise: Promise) { 81 | RNPermissionsModuleImpl.requestLocationAccuracy(promise) 82 | } 83 | 84 | @ReactMethod 85 | fun openPhotoPicker(promise: Promise) { 86 | RNPermissionsModuleImpl.openPhotoPicker(promise) 87 | } 88 | 89 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray): Boolean { 90 | return RNPermissionsModuleImpl.onRequestPermissionsResult(reactApplicationContext, callbacks, requestCode, grantResults) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/commonjs/expo'); 2 | -------------------------------------------------------------------------------- /docs/location_always_first_prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/docs/location_always_first_prompt.png -------------------------------------------------------------------------------- /docs/location_always_second_prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/docs/location_always_second_prompt.png -------------------------------------------------------------------------------- /docs/location_always_upgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/docs/location_always_upgrade.png -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/.yarnrc: -------------------------------------------------------------------------------- 1 | save-exact true 2 | -------------------------------------------------------------------------------- /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.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | -------------------------------------------------------------------------------- /example/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.2.2.1) 9 | base64 10 | benchmark (>= 0.3) 11 | bigdecimal 12 | concurrent-ruby (~> 1.0, >= 1.3.1) 13 | connection_pool (>= 2.2.5) 14 | drb 15 | i18n (>= 1.6, < 2) 16 | logger (>= 1.4.2) 17 | minitest (>= 5.1) 18 | securerandom (>= 0.3) 19 | tzinfo (~> 2.0, >= 2.0.5) 20 | addressable (2.8.7) 21 | public_suffix (>= 2.0.2, < 7.0) 22 | algoliasearch (1.27.5) 23 | httpclient (~> 2.8, >= 2.8.3) 24 | json (>= 1.5.1) 25 | atomos (0.1.3) 26 | base64 (0.2.0) 27 | benchmark (0.4.0) 28 | bigdecimal (3.1.9) 29 | claide (1.1.0) 30 | cocoapods (1.15.2) 31 | addressable (~> 2.8) 32 | claide (>= 1.0.2, < 2.0) 33 | cocoapods-core (= 1.15.2) 34 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 35 | cocoapods-downloader (>= 2.1, < 3.0) 36 | cocoapods-plugins (>= 1.0.0, < 2.0) 37 | cocoapods-search (>= 1.0.0, < 2.0) 38 | cocoapods-trunk (>= 1.6.0, < 2.0) 39 | cocoapods-try (>= 1.1.0, < 2.0) 40 | colored2 (~> 3.1) 41 | escape (~> 0.0.4) 42 | fourflusher (>= 2.3.0, < 3.0) 43 | gh_inspector (~> 1.0) 44 | molinillo (~> 0.8.0) 45 | nap (~> 1.0) 46 | ruby-macho (>= 2.3.0, < 3.0) 47 | xcodeproj (>= 1.23.0, < 2.0) 48 | cocoapods-core (1.15.2) 49 | activesupport (>= 5.0, < 8) 50 | addressable (~> 2.8) 51 | algoliasearch (~> 1.0) 52 | concurrent-ruby (~> 1.1) 53 | fuzzy_match (~> 2.0.4) 54 | nap (~> 1.0) 55 | netrc (~> 0.11) 56 | public_suffix (~> 4.0) 57 | typhoeus (~> 1.0) 58 | cocoapods-deintegrate (1.0.5) 59 | cocoapods-downloader (2.1) 60 | cocoapods-plugins (1.0.0) 61 | nap 62 | cocoapods-search (1.0.1) 63 | cocoapods-trunk (1.6.0) 64 | nap (>= 0.8, < 2.0) 65 | netrc (~> 0.11) 66 | cocoapods-try (1.2.0) 67 | colored2 (3.1.2) 68 | concurrent-ruby (1.3.3) 69 | connection_pool (2.5.1) 70 | drb (2.2.1) 71 | escape (0.0.4) 72 | ethon (0.16.0) 73 | ffi (>= 1.15.0) 74 | ffi (1.17.2) 75 | fourflusher (2.3.1) 76 | fuzzy_match (2.0.4) 77 | gh_inspector (1.1.3) 78 | httpclient (2.9.0) 79 | mutex_m 80 | i18n (1.14.7) 81 | concurrent-ruby (~> 1.0) 82 | json (2.10.2) 83 | logger (1.7.0) 84 | minitest (5.25.5) 85 | molinillo (0.8.0) 86 | mutex_m (0.3.0) 87 | nanaimo (0.3.0) 88 | nap (1.1.0) 89 | netrc (0.11.0) 90 | nkf (0.2.0) 91 | public_suffix (4.0.7) 92 | rexml (3.4.1) 93 | ruby-macho (2.5.1) 94 | securerandom (0.4.1) 95 | typhoeus (1.4.1) 96 | ethon (>= 0.9.0) 97 | tzinfo (2.0.6) 98 | concurrent-ruby (~> 1.0) 99 | xcodeproj (1.25.1) 100 | CFPropertyList (>= 2.3.3, < 4.0) 101 | atomos (~> 0.1.3) 102 | claide (>= 1.0.2, < 2.0) 103 | colored2 (~> 3.1) 104 | nanaimo (~> 0.3.0) 105 | rexml (>= 3.3.6, < 4.0) 106 | 107 | PLATFORMS 108 | ruby 109 | 110 | DEPENDENCIES 111 | activesupport (>= 6.1.7.5, != 7.1.0) 112 | cocoapods (>= 1.13, != 1.15.1, != 1.15.0) 113 | concurrent-ruby (< 1.3.4) 114 | xcodeproj (< 1.26.0) 115 | 116 | RUBY VERSION 117 | ruby 3.3.1p55 118 | 119 | BUNDLED WITH 120 | 2.5.9 121 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "org.jetbrains.kotlin.android" 3 | apply plugin: "com.facebook.react" 4 | 5 | /** 6 | * This is the configuration block to customize your React Native Android app. 7 | * By default you don't need to apply any configuration, just uncomment the lines you need. 8 | */ 9 | react { 10 | /* Folders */ 11 | // The root of your project, i.e. where "package.json" lives. Default is '../..' 12 | // root = file("../../") 13 | // The folder where the react-native NPM package is. Default is ../../node_modules/react-native 14 | // reactNativeDir = file("../../node_modules/react-native") 15 | // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen 16 | // codegenDir = file("../../node_modules/@react-native/codegen") 17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js 18 | // cliFile = file("../../node_modules/react-native/cli.js") 19 | 20 | /* Variants */ 21 | // The list of variants to that are debuggable. For those we're going to 22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 24 | // debuggableVariants = ["liteDebug", "prodDebug"] 25 | 26 | /* Bundling */ 27 | // A list containing the node command and its flags. Default is just 'node'. 28 | // nodeExecutableAndArgs = ["node"] 29 | // 30 | // The command to run when bundling. By default is 'bundle' 31 | // bundleCommand = "ram-bundle" 32 | // 33 | // The path to the CLI configuration file. Default is empty. 34 | // bundleConfig = file(../rn-cli.config.js) 35 | // 36 | // The name of the generated asset file containing your JS bundle 37 | // bundleAssetName = "MyApplication.android.bundle" 38 | // 39 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 40 | // entryFile = file("../js/MyApplication.android.js") 41 | // 42 | // A list of extra flags to pass to the 'bundle' commands. 43 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 44 | // extraPackagerArgs = [] 45 | 46 | /* Hermes Commands */ 47 | // The hermes compiler command to run. By default it is 'hermesc' 48 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" 49 | // 50 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 51 | // hermesFlags = ["-O", "-output-source-map"] 52 | 53 | /* Autolinking */ 54 | autolinkLibrariesWithApp() 55 | } 56 | 57 | /** 58 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 59 | */ 60 | def enableProguardInReleaseBuilds = false 61 | 62 | /** 63 | * The preferred build flavor of JavaScriptCore (JSC) 64 | * 65 | * For example, to use the international variant, you can use: 66 | * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+` 67 | * 68 | * The international variant includes ICU i18n library and necessary data 69 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 70 | * give correct results when using with locales other than en-US. Note that 71 | * this variant is about 6MiB larger per architecture than default. 72 | */ 73 | def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' 74 | 75 | android { 76 | ndkVersion rootProject.ext.ndkVersion 77 | buildToolsVersion rootProject.ext.buildToolsVersion 78 | compileSdk rootProject.ext.compileSdkVersion 79 | 80 | namespace "com.rnpermissionsexample" 81 | defaultConfig { 82 | applicationId "com.rnpermissionsexample" 83 | minSdkVersion rootProject.ext.minSdkVersion 84 | targetSdkVersion rootProject.ext.targetSdkVersion 85 | versionCode 1 86 | versionName "1.0" 87 | } 88 | signingConfigs { 89 | debug { 90 | storeFile file('debug.keystore') 91 | storePassword 'android' 92 | keyAlias 'androiddebugkey' 93 | keyPassword 'android' 94 | } 95 | } 96 | buildTypes { 97 | debug { 98 | signingConfig signingConfigs.debug 99 | } 100 | release { 101 | // Caution! In production, you need to generate your own keystore file. 102 | // see https://reactnative.dev/docs/signed-apk-android. 103 | signingConfig signingConfigs.debug 104 | minifyEnabled enableProguardInReleaseBuilds 105 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 106 | } 107 | } 108 | } 109 | 110 | dependencies { 111 | // The version of react-native is set by the React Native Gradle Plugin 112 | implementation("com.facebook.react:react-android") 113 | 114 | if (hermesEnabled.toBoolean()) { 115 | implementation("com.facebook.react:hermes-android") 116 | } else { 117 | implementation jscFlavor 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 57 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /example/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/rnpermissionsexample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.rnpermissionsexample 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "RNPermissionsExample" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/rnpermissionsexample/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.rnpermissionsexample 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeHost 8 | import com.facebook.react.ReactPackage 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | import com.facebook.react.soloader.OpenSourceMergedSoMapping 13 | import com.facebook.soloader.SoLoader 14 | 15 | class MainApplication : Application(), ReactApplication { 16 | 17 | override val reactNativeHost: ReactNativeHost = 18 | object : DefaultReactNativeHost(this) { 19 | override fun getPackages(): List = 20 | PackageList(this).packages.apply { 21 | // Packages that cannot be autolinked yet can be added manually here, for example: 22 | // add(MyReactNativePackage()) 23 | } 24 | 25 | override fun getJSMainModuleName(): String = "index" 26 | 27 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 28 | 29 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 30 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 31 | } 32 | 33 | override val reactHost: ReactHost 34 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 35 | 36 | override fun onCreate() { 37 | super.onCreate() 38 | SoLoader.init(this, OpenSourceMergedSoMapping) 39 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 40 | // If you opted-in for the New Architecture, we load the native entry point for this app. 41 | load() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RNPermissionsExample 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.0.21" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /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 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/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-8.12-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } 4 | rootProject.name = 'RNPermissionsExample' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RNPermissionsExample", 3 | "displayName": "RNPermissionsExample" 4 | } 5 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pkg = require('../package.json'); 3 | 4 | const resolverConfig = { 5 | extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], 6 | alias: {[pkg.name]: path.resolve(__dirname, '../src')}, 7 | }; 8 | 9 | module.exports = { 10 | presets: ['module:@react-native/babel-preset'], 11 | plugins: [['module-resolver', resolverConfig]], 12 | }; 13 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AppRegistry} from 'react-native'; 3 | import {Provider as PaperProvider} from 'react-native-paper'; 4 | import {name as appName} from './app.json'; 5 | import {App} from './src/App'; 6 | 7 | let Main = () => ( 8 | 9 | 10 | 11 | ); 12 | 13 | AppRegistry.registerComponent(appName, () => Main); 14 | -------------------------------------------------------------------------------- /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 | # NODE_BINARY variable contains the PATH to the node executable. 6 | # 7 | # Customize the NODE_BINARY variable here. 8 | # For example, to use nvm with brew, add the following line 9 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 10 | export NODE_BINARY=$(command -v node) 11 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | def node_require(script) 2 | # Resolve script with node to allow for hoisting 3 | require Pod::Executable.execute_command('node', ['-p', 4 | "require.resolve( 5 | '#{script}', 6 | {paths: [process.argv[1]]}, 7 | )", __dir__]).strip 8 | end 9 | 10 | node_require('react-native/scripts/react_native_pods.rb') 11 | node_require('react-native-permissions/scripts/setup.rb') 12 | 13 | platform :ios, min_ios_version_supported 14 | prepare_react_native_project! 15 | 16 | setup_permissions([ 17 | 'AppTrackingTransparency', 18 | 'Bluetooth', 19 | 'Calendars', 20 | 'CalendarsWriteOnly', 21 | 'Camera', 22 | 'Contacts', 23 | 'FaceID', 24 | 'LocationAccuracy', 25 | 'LocationAlways', 26 | 'LocationWhenInUse', 27 | 'MediaLibrary', 28 | 'Microphone', 29 | 'Motion', 30 | 'Notifications', 31 | 'PhotoLibrary', 32 | 'PhotoLibraryAddOnly', 33 | 'Reminders', 34 | # 'Siri', 35 | 'SpeechRecognition', 36 | 'StoreKit', 37 | ]) 38 | 39 | linkage = ENV['USE_FRAMEWORKS'] 40 | if linkage != nil 41 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 42 | use_frameworks! :linkage => linkage.to_sym 43 | end 44 | 45 | target 'RNPermissionsExample' do 46 | config = use_native_modules! 47 | 48 | use_react_native!( 49 | :path => config[:reactNativePath], 50 | # An absolute path to your application root. 51 | :app_path => "#{Pod::Config.instance.installation_root}/.." 52 | ) 53 | 54 | post_install do |installer| 55 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 56 | react_native_post_install( 57 | installer, 58 | config[:reactNativePath], 59 | :mac_catalyst_enabled => false, 60 | # :ccache_enabled => true 61 | ) 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample.xcodeproj/xcshareddata/xcschemes/RNPermissionsExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: RCTAppDelegate { 8 | override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 9 | self.moduleName = "RNPermissionsExample" 10 | self.dependencyProvider = RCTAppDependencyProvider() 11 | 12 | // You can add your custom initial props in the dictionary below. 13 | // They will be passed down to the ViewController used by React Native. 14 | self.initialProps = [:] 15 | 16 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 17 | } 18 | 19 | override func sourceURL(for bridge: RCTBridge) -> URL? { 20 | self.bundleURL() 21 | } 22 | 23 | override func bundleURL() -> URL? { 24 | #if DEBUG 25 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 26 | #else 27 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 28 | #endif 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample/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/RNPermissionsExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | RNPermissionsExample 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 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSAppleMusicUsageDescription 35 | Let me use your media library 36 | NSBluetoothAlwaysUsageDescription 37 | Let me use bluetooth 38 | NSBluetoothPeripheralUsageDescription 39 | Let me use bluetooth 40 | NSCalendarsFullAccessUsageDescription 41 | Let me use your calendars 42 | NSCalendarsWriteOnlyAccessUsageDescription 43 | Let me use your calendars 44 | NSCameraUsageDescription 45 | Let me use the camera 46 | NSContactsUsageDescription 47 | Let me use your contacts 48 | NSFaceIDUsageDescription 49 | Let me use FaceID 50 | NSLocationAlwaysAndWhenInUseUsageDescription 51 | Let me use your location, even in background 52 | NSLocationTemporaryUsageDescriptionDictionary 53 | 54 | full-accuracy 55 | Let me use your precise location temporarily 56 | 57 | NSLocationWhenInUseUsageDescription 58 | Let me use your location when the app is opened 59 | NSMicrophoneUsageDescription 60 | Let me use the microphone 61 | NSMotionUsageDescription 62 | Let me use your motion data 63 | NSPhotoLibraryAddUsageDescription 64 | Let me add photos 65 | NSPhotoLibraryUsageDescription 66 | Let me use your photo library 67 | NSRemindersFullAccessUsageDescription 68 | Let me use your reminders 69 | NSSpeechRecognitionUsageDescription 70 | Let me use speech recognition 71 | NSUserTrackingUsageDescription 72 | Let me use your ad identifier 73 | UIAppFonts 74 | 75 | MaterialCommunityIcons.ttf 76 | 77 | UIBackgroundModes 78 | 79 | bluetooth-peripheral 80 | location 81 | 82 | UILaunchStoryboardName 83 | LaunchScreen 84 | UIRequiredDeviceCapabilities 85 | 86 | arm64 87 | 88 | UISupportedInterfaceOrientations 89 | 90 | UIInterfaceOrientationPortrait 91 | 92 | UIViewControllerBasedStatusBarAppearance 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /example/ios/RNPermissionsExample/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryUserDefaults 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | CA92.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryFileTimestamp 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | C617.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pkg = require('../package.json'); 3 | 4 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); 5 | const escape = require('escape-string-regexp'); 6 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 7 | 8 | const peerDependencies = Object.keys(pkg.peerDependencies); 9 | const root = path.resolve(__dirname, '..'); 10 | const projectNodeModules = path.join(__dirname, 'node_modules'); 11 | const rootNodeModules = path.join(root, 'node_modules'); 12 | 13 | // We need to make sure that only one version is loaded for peerDependencies 14 | // So we block them at the root, and alias them to the versions in example's node_modules 15 | const blacklistRE = exclusionList( 16 | peerDependencies.map((name) => new RegExp(`^${escape(path.join(rootNodeModules, name))}\\/.*$`)), 17 | ); 18 | 19 | const extraNodeModules = peerDependencies.reduce((acc, name) => { 20 | acc[name] = path.join(projectNodeModules, name); 21 | return acc; 22 | }, {}); 23 | 24 | /** 25 | * Metro configuration 26 | * https://reactnative.dev/docs/metro 27 | * 28 | * @type {import('@react-native/metro-config').MetroConfig} 29 | */ 30 | const config = { 31 | projectRoot: __dirname, 32 | watchFolders: [root], 33 | resolver: {blacklistRE, extraNodeModules}, 34 | }; 35 | 36 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 37 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-permissions-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "engines": { 6 | "node": "^22" 7 | }, 8 | "scripts": { 9 | "pod-backup": "cp ../RNPermissions.podspec ../RNPermissions.podspec.bak", 10 | "pod-restore": "mv ../RNPermissions.podspec.bak ../RNPermissions.podspec", 11 | "pod-update": "yarn pod-backup && cd ios && bundle install && bundle exec pod update && cd .. && yarn pod-restore", 12 | "pod-install": "yarn pod-backup && cd ios && bundle install && bundle exec pod install && cd .. && yarn pod-restore", 13 | "clean": "rm -rf ./node_modules ./ios/Pods", 14 | "preinstall": "cd .. && yarn && yarn build && cd example", 15 | "postinstall": "yarn pod-install", 16 | "start": "react-native start", 17 | "reinstall": "yarn clean && yarn install" 18 | }, 19 | "dependencies": { 20 | "react": "19.0.0", 21 | "react-native": "0.78.2", 22 | "react-native-paper": "^5.13.3", 23 | "react-native-permissions": "link:../", 24 | "react-native-safe-area-context": "^5.4.0", 25 | "react-native-vector-icons": "^10.2.0", 26 | "react-native-windows": "0.78.4" 27 | }, 28 | "devDependencies": { 29 | "@babel/core": "^7.25.2", 30 | "@babel/preset-env": "^7.25.3", 31 | "@babel/runtime": "^7.25.0", 32 | "@react-native-community/cli": "15.0.1", 33 | "@react-native-community/cli-platform-android": "15.0.1", 34 | "@react-native-community/cli-platform-ios": "15.0.1", 35 | "@react-native/babel-preset": "0.78.2", 36 | "@react-native/metro-config": "0.78.2", 37 | "@types/react": "^19.0.0", 38 | "babel-plugin-module-resolver": "^5.0.2", 39 | "typescript": "^5.8.3" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "lib": ["ES2017"], 5 | "jsx": "react-native", 6 | "moduleResolution": "Node", 7 | 8 | "allowJs": false, 9 | "strict": true, 10 | "declaration": true, 11 | "sourceMap": true, 12 | "stripInternal": true, 13 | "skipLibCheck": true, 14 | "verbatimModuleSyntax": true, 15 | 16 | "allowUnreachableCode": false, 17 | "allowUnusedLabels": false, 18 | "noFallthroughCasesInSwitch": true, 19 | "noImplicitOverride": true, 20 | "noImplicitReturns": false, 21 | "noUncheckedIndexedAccess": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | 25 | "paths": { 26 | "react-native-permissions": ["../src"] 27 | } 28 | }, 29 | "include": ["src"], 30 | "exclude": ["node_modules", "babel.config.js", "metro.config.js"] 31 | } 32 | -------------------------------------------------------------------------------- /example/windows/.gitignore: -------------------------------------------------------------------------------- 1 | *AppPackages* 2 | *BundleArtifacts* 3 | 4 | #OS junk files 5 | [Tt]humbs.db 6 | *.DS_Store 7 | 8 | #Visual Studio files 9 | *.[Oo]bj 10 | *.user 11 | *.aps 12 | *.pch 13 | *.vspscc 14 | *.vssscc 15 | *_i.c 16 | *_p.c 17 | *.ncb 18 | *.suo 19 | *.tlb 20 | *.tlh 21 | *.bak 22 | *.[Cc]ache 23 | *.ilk 24 | *.log 25 | *.lib 26 | *.sbr 27 | *.sdf 28 | *.opensdf 29 | *.opendb 30 | *.unsuccessfulbuild 31 | ipch/ 32 | [Oo]bj/ 33 | [Bb]in 34 | [Dd]ebug*/ 35 | [Rr]elease*/ 36 | Ankh.NoLoad 37 | 38 | # Visual C++ cache files 39 | ipch/ 40 | *.aps 41 | *.ncb 42 | *.opendb 43 | *.opensdf 44 | *.sdf 45 | *.cachefile 46 | *.VC.db 47 | *.VC.VC.opendb 48 | 49 | #MonoDevelop 50 | *.pidb 51 | *.userprefs 52 | 53 | #Tooling 54 | _ReSharper*/ 55 | *.resharper 56 | [Tt]est[Rr]esult* 57 | *.sass-cache 58 | 59 | #Project files 60 | [Bb]uild/ 61 | 62 | #Subversion files 63 | .svn 64 | 65 | # Office Temp Files 66 | ~$* 67 | 68 | # vim Temp Files 69 | *~ 70 | 71 | #NuGet 72 | packages/ 73 | *.nupkg 74 | 75 | #ncrunch 76 | *ncrunch* 77 | *crunch*.local.xml 78 | 79 | # visual studio database projects 80 | *.dbmdl 81 | 82 | #Test files 83 | *.testsettings 84 | 85 | #Other files 86 | *.DotSettings 87 | .vs/ 88 | *project.lock.json 89 | 90 | #Files generated by the VS build 91 | **/Generated Files/** 92 | 93 | -------------------------------------------------------------------------------- /example/windows/Example/.gitignore: -------------------------------------------------------------------------------- 1 | /Bundle 2 | -------------------------------------------------------------------------------- /example/windows/Example/App.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "App.h" 4 | 5 | #include "AutolinkedNativeModules.g.h" 6 | #include "ReactPackageProvider.h" 7 | 8 | 9 | using namespace winrt::Example; 10 | using namespace winrt::Example::implementation; 11 | 12 | /// 13 | /// Initializes the singleton application object. This is the first line of 14 | /// authored code executed, and as such is the logical equivalent of main() or 15 | /// WinMain(). 16 | /// 17 | App::App() noexcept 18 | { 19 | MainComponentName(L"RNPermissionsExample"); 20 | 21 | #if BUNDLE 22 | JavaScriptBundleFile(L"index.windows"); 23 | InstanceSettings().UseWebDebugger(false); 24 | InstanceSettings().UseFastRefresh(false); 25 | #else 26 | JavaScriptMainModuleName(L"index"); 27 | InstanceSettings().UseWebDebugger(true); 28 | InstanceSettings().UseFastRefresh(true); 29 | #endif 30 | 31 | #if _DEBUG 32 | InstanceSettings().EnableDeveloperMenu(true); 33 | #else 34 | InstanceSettings().EnableDeveloperMenu(false); 35 | #endif 36 | 37 | RegisterAutolinkedNativeModulePackages(PackageProviders()); // Includes any autolinked modules 38 | 39 | PackageProviders().Append(make()); // Includes all modules in this project 40 | PackageProviders().Append(winrt::RNPermissions::ReactPackageProvider()); 41 | 42 | InitializeComponent(); 43 | } 44 | -------------------------------------------------------------------------------- /example/windows/Example/App.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "App.xaml.g.h" 4 | 5 | namespace winrt::Example::implementation 6 | { 7 | struct App : AppT 8 | { 9 | App() noexcept; 10 | }; 11 | } // namespace winrt::Example::implementation 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/windows/Example/App.idl: -------------------------------------------------------------------------------- 1 | namespace Example 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /example/windows/Example/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/windows/Example/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /example/windows/Example/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /example/windows/Example/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /example/windows/Example/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /example/windows/Example/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /example/windows/Example/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/StoreLogo.png -------------------------------------------------------------------------------- /example/windows/Example/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /example/windows/Example/AutolinkedNativeModules.g.cpp: -------------------------------------------------------------------------------- 1 | // AutolinkedNativeModules.g.cpp contents generated by "react-native autolink-windows" 2 | #include "pch.h" 3 | #include "AutolinkedNativeModules.g.h" 4 | 5 | 6 | namespace winrt::Microsoft::ReactNative 7 | { 8 | 9 | void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders) 10 | { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example/windows/Example/AutolinkedNativeModules.g.h: -------------------------------------------------------------------------------- 1 | // AutolinkedNativeModules.g.h contents generated by "react-native autolink-windows" 2 | #pragma once 3 | 4 | 5 | namespace winrt::Microsoft::ReactNative 6 | { 7 | 8 | void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /example/windows/Example/Example.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Assets 25 | 26 | 27 | Assets 28 | 29 | 30 | Assets 31 | 32 | 33 | Assets 34 | 35 | 36 | Assets 37 | 38 | 39 | Assets 40 | 41 | 42 | Assets 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | {e48dc53e-40b1-40cb-970a-f89935452892} 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /example/windows/Example/Example_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/example/windows/Example/Example_TemporaryKey.pfx -------------------------------------------------------------------------------- /example/windows/Example/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | Example 23 | ja 24 | Assets\StoreLogo.png 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /example/windows/Example/PropertySheet.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /example/windows/Example/ReactPackageProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ReactPackageProvider.h" 3 | #include "NativeModules.h" 4 | 5 | 6 | using namespace winrt::Microsoft::ReactNative; 7 | 8 | namespace winrt::Example::implementation 9 | { 10 | 11 | void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept 12 | { 13 | AddAttributedModules(packageBuilder); 14 | } 15 | 16 | } // namespace winrt::Example::implementation 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/windows/Example/ReactPackageProvider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "winrt/Microsoft.ReactNative.h" 4 | 5 | 6 | namespace winrt::Example::implementation 7 | { 8 | struct ReactPackageProvider : winrt::implements 9 | { 10 | public: // IReactPackageProvider 11 | void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept; 12 | }; 13 | } // namespace winrt::Example::implementation 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/windows/Example/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example/windows/Example/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /example/windows/Example/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NOMINMAX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "winrt/RNPermissions.h" 29 | -------------------------------------------------------------------------------- /fetchWindowsCapabilites.js: -------------------------------------------------------------------------------- 1 | // Fetch list of Windows UWP App capabilites from the Microsoft docs 2 | // The names of individual capabilites are in tag and follow camelCase 3 | 4 | const https = require('https'); 5 | const {EOL} = require('os'); 6 | 7 | https.get( 8 | 'https://docs.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations', 9 | (res) => { 10 | res.setEncoding('utf8'); 11 | 12 | let data = ''; 13 | 14 | res.on('error', ({message}) => { 15 | console.error(message); 16 | process.exit(-1); 17 | }); 18 | 19 | res.on('data', (chunk) => { 20 | data += chunk; 21 | }); 22 | 23 | res.on('end', () => parse(data)); 24 | }, 25 | ); 26 | 27 | function parse(data) { 28 | const names = new Set(); 29 | 30 | for (const match of data.match(/[a-z]+[a-zA-Z\.]*<\/strong>/gm)) { 31 | names.add( 32 | match.substr(''.length, match.length - ''.length - ''.length), 33 | ); 34 | } 35 | 36 | const results = []; 37 | 38 | for (const name of names) { 39 | let constName = ''; 40 | 41 | for (let i = 0; i < name.length; ++i) { 42 | const char = name.charAt(i); 43 | 44 | if (char === char.toUpperCase()) { 45 | constName += '_'; 46 | } 47 | 48 | constName += char.toUpperCase(); 49 | } 50 | 51 | constName = constName.replace('WI_FI', 'WIFI'); 52 | constName = constName.replace('VO_I_P', 'VOIP'); 53 | results.push(`${constName}: 'windows.permission.${name}',`); 54 | } 55 | 56 | console.log(results.sort().join(EOL)); 57 | } 58 | -------------------------------------------------------------------------------- /ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerAppTrackingTransparency : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerAppTrackingTransparency.h" 2 | 3 | #import 4 | #import 5 | 6 | @interface RNPermissionHandlerAppTrackingTransparency() 7 | 8 | @property (nonatomic, strong) void (^resolve)(RNPermissionStatus status); 9 | 10 | @end 11 | 12 | @implementation RNPermissionHandlerAppTrackingTransparency 13 | 14 | + (NSArray * _Nonnull)usageDescriptionKeys { 15 | return @[@"NSUserTrackingUsageDescription"]; 16 | } 17 | 18 | + (NSString * _Nonnull)handlerUniqueId { 19 | return @"ios.permission.APP_TRACKING_TRANSPARENCY"; 20 | } 21 | 22 | - (RNPermissionStatus)convertStatus:(ATTrackingManagerAuthorizationStatus)status API_AVAILABLE(ios(14)) { 23 | switch (status) { 24 | case ATTrackingManagerAuthorizationStatusNotDetermined: 25 | return RNPermissionStatusNotDetermined; 26 | case ATTrackingManagerAuthorizationStatusRestricted: 27 | return RNPermissionStatusRestricted; 28 | case ATTrackingManagerAuthorizationStatusDenied: 29 | return RNPermissionStatusDenied; 30 | case ATTrackingManagerAuthorizationStatusAuthorized: 31 | return RNPermissionStatusAuthorized; 32 | } 33 | } 34 | 35 | - (RNPermissionStatus)currentStatus { 36 | if (@available(iOS 14.0, tvOS 14.0, *)) { 37 | return [self convertStatus:[ATTrackingManager trackingAuthorizationStatus]]; 38 | } else { 39 | if ([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]) { 40 | return RNPermissionStatusAuthorized; 41 | } else { 42 | return RNPermissionStatusDenied; 43 | } 44 | } 45 | } 46 | 47 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 48 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 49 | if (@available(iOS 14.0, tvOS 14.0, *)) { 50 | if ([ATTrackingManager trackingAuthorizationStatus] != ATTrackingManagerAuthorizationStatusNotDetermined) { 51 | return resolve([self currentStatus]); 52 | } 53 | 54 | if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) { 55 | [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) { 56 | resolve([self convertStatus:status]); 57 | }]; 58 | } else { 59 | _resolve = resolve; 60 | 61 | [[NSNotificationCenter defaultCenter] addObserver:self 62 | selector:@selector(onApplicationDidBecomeActive:) 63 | name:UIApplicationDidBecomeActiveNotification 64 | object:nil]; 65 | } 66 | } else { 67 | resolve([self currentStatus]); 68 | } 69 | } 70 | 71 | - (void)onApplicationDidBecomeActive:(__unused NSNotification *)notification { 72 | [[NSNotificationCenter defaultCenter] removeObserver:self 73 | name:UIApplicationDidBecomeActiveNotification 74 | object:nil]; 75 | 76 | if (@available(iOS 14.0, tvOS 14.0, *)) { 77 | [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) { 78 | self->_resolve([self convertStatus:status]); 79 | }]; 80 | } 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /ios/Bluetooth/RNPermissionHandlerBluetooth.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerBluetooth : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Bluetooth/RNPermissionHandlerBluetooth.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerBluetooth.h" 2 | 3 | #import 4 | 5 | @interface RNPermissionHandlerBluetooth() 6 | 7 | @property (nonatomic, strong) CBPeripheralManager* manager; 8 | @property (nonatomic, strong) void (^resolve)(RNPermissionStatus status); 9 | 10 | @end 11 | 12 | @implementation RNPermissionHandlerBluetooth 13 | 14 | + (NSArray * _Nonnull)usageDescriptionKeys { 15 | return @[ 16 | @"NSBluetoothAlwaysUsageDescription", 17 | @"NSBluetoothPeripheralUsageDescription", 18 | ]; 19 | } 20 | 21 | + (NSString * _Nonnull)handlerUniqueId { 22 | return @"ios.permission.BLUETOOTH"; 23 | } 24 | 25 | - (RNPermissionStatus)currentStatus { 26 | #if TARGET_OS_TV || TARGET_OS_SIMULATOR 27 | return RNPermissionStatusNotAvailable; 28 | #else 29 | switch ([CBManager authorization]) { 30 | case CBManagerAuthorizationNotDetermined: 31 | return RNPermissionStatusNotDetermined; 32 | case CBManagerAuthorizationRestricted: 33 | return RNPermissionStatusRestricted; 34 | case CBManagerAuthorizationDenied: 35 | return RNPermissionStatusDenied; 36 | case CBManagerAuthorizationAllowedAlways: 37 | return RNPermissionStatusAuthorized; 38 | } 39 | #endif 40 | } 41 | 42 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 43 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 44 | #if TARGET_OS_TV || TARGET_OS_SIMULATOR 45 | return resolve(RNPermissionStatusNotAvailable); 46 | #else 47 | _resolve = resolve; 48 | 49 | _manager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:@{ 50 | CBPeripheralManagerOptionShowPowerAlertKey: @false, 51 | }]; 52 | #endif 53 | } 54 | 55 | - (void)peripheralManagerDidUpdateState:(nonnull CBPeripheralManager *)peripheral { 56 | switch (peripheral.state) { 57 | case CBManagerStatePoweredOff: 58 | case CBManagerStateResetting: 59 | case CBManagerStateUnsupported: 60 | return _resolve(RNPermissionStatusNotAvailable); 61 | case CBManagerStateUnknown: 62 | return _resolve(RNPermissionStatusNotDetermined); 63 | case CBManagerStateUnauthorized: 64 | return _resolve(RNPermissionStatusDenied); 65 | case CBManagerStatePoweredOn: 66 | return _resolve([self currentStatus]); 67 | } 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /ios/Calendars/RNPermissionHandlerCalendars.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerCalendars : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Calendars/RNPermissionHandlerCalendars.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerCalendars.h" 2 | 3 | #if !TARGET_OS_TV 4 | #import 5 | #endif 6 | 7 | @implementation RNPermissionHandlerCalendars 8 | 9 | + (NSArray * _Nonnull)usageDescriptionKeys { 10 | return @[@"NSCalendarsFullAccessUsageDescription"]; 11 | } 12 | 13 | + (NSString * _Nonnull)handlerUniqueId { 14 | return @"ios.permission.CALENDARS"; 15 | } 16 | 17 | - (RNPermissionStatus)currentStatus { 18 | #if TARGET_OS_TV 19 | return RNPermissionStatusNotAvailable; 20 | #else 21 | switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]) { 22 | case EKAuthorizationStatusNotDetermined: 23 | return RNPermissionStatusNotDetermined; 24 | case EKAuthorizationStatusRestricted: 25 | return RNPermissionStatusRestricted; 26 | case EKAuthorizationStatusDenied: 27 | return RNPermissionStatusDenied; 28 | case EKAuthorizationStatusWriteOnly: 29 | return [RNPermissions isFlaggedAsRequested:[[self class] handlerUniqueId]] ? RNPermissionStatusDenied : RNPermissionStatusNotDetermined; 30 | case EKAuthorizationStatusFullAccess: 31 | return RNPermissionStatusAuthorized; 32 | } 33 | #endif 34 | } 35 | 36 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 37 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 38 | #if TARGET_OS_TV 39 | resolve(RNPermissionStatusNotAvailable); 40 | #else 41 | void (^completion)(BOOL, NSError * _Nullable) = ^(BOOL granted, NSError * _Nullable error) { 42 | if (error != nil) { 43 | reject(error); 44 | } else { 45 | [RNPermissions flagAsRequested:[[self class] handlerUniqueId]]; 46 | 47 | if (granted) { 48 | return resolve(RNPermissionStatusAuthorized); 49 | } 50 | 51 | switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]) { 52 | case EKAuthorizationStatusNotDetermined: 53 | return resolve(RNPermissionStatusNotDetermined); 54 | case EKAuthorizationStatusRestricted: 55 | return resolve(RNPermissionStatusRestricted); 56 | case EKAuthorizationStatusDenied: 57 | case EKAuthorizationStatusWriteOnly: 58 | return resolve(RNPermissionStatusDenied); 59 | case EKAuthorizationStatusFullAccess: 60 | return resolve(RNPermissionStatusAuthorized); 61 | } 62 | } 63 | }; 64 | 65 | EKEventStore *store = [EKEventStore new]; 66 | 67 | if (@available(iOS 17.0, *)) { 68 | [store requestFullAccessToEventsWithCompletion:completion]; 69 | } else { 70 | [store requestAccessToEntityType:EKEntityTypeEvent completion:completion]; 71 | } 72 | #endif 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /ios/CalendarsWriteOnly/RNPermissionHandlerCalendarsWriteOnly.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerCalendarsWriteOnly : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/CalendarsWriteOnly/RNPermissionHandlerCalendarsWriteOnly.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerCalendarsWriteOnly.h" 2 | 3 | #if !TARGET_OS_TV 4 | #import 5 | #endif 6 | 7 | @implementation RNPermissionHandlerCalendarsWriteOnly 8 | 9 | + (NSArray * _Nonnull)usageDescriptionKeys { 10 | return @[@"NSCalendarsWriteOnlyAccessUsageDescription"]; 11 | } 12 | 13 | + (NSString * _Nonnull)handlerUniqueId { 14 | return @"ios.permission.CALENDARS_WRITE_ONLY"; 15 | } 16 | 17 | - (RNPermissionStatus)currentStatus { 18 | #if TARGET_OS_TV 19 | return RNPermissionStatusNotAvailable; 20 | #else 21 | switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]) { 22 | case EKAuthorizationStatusNotDetermined: 23 | return RNPermissionStatusNotDetermined; 24 | case EKAuthorizationStatusRestricted: 25 | return RNPermissionStatusRestricted; 26 | case EKAuthorizationStatusDenied: 27 | return RNPermissionStatusDenied; 28 | case EKAuthorizationStatusWriteOnly: 29 | case EKAuthorizationStatusFullAccess: 30 | return RNPermissionStatusAuthorized; 31 | } 32 | #endif 33 | } 34 | 35 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 36 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 37 | #if TARGET_OS_TV 38 | resolve(RNPermissionStatusNotAvailable); 39 | #else 40 | void (^completion)(BOOL, NSError * _Nullable) = ^(BOOL granted, NSError * _Nullable error) { 41 | if (error != nil) { 42 | reject(error); 43 | } else { 44 | resolve(granted ? RNPermissionStatusAuthorized : [self currentStatus]); 45 | } 46 | }; 47 | 48 | EKEventStore *store = [EKEventStore new]; 49 | 50 | if (@available(iOS 17.0, *)) { 51 | [store requestWriteOnlyAccessToEventsWithCompletion:completion]; 52 | } else { 53 | [store requestAccessToEntityType:EKEntityTypeEvent completion:completion]; 54 | } 55 | #endif 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ios/Camera/RNPermissionHandlerCamera.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerCamera : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Camera/RNPermissionHandlerCamera.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerCamera.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerCamera 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSCameraUsageDescription"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.CAMERA"; 13 | } 14 | 15 | - (RNPermissionStatus)currentStatus { 16 | if (@available(iOS 7.0, tvOS 17.0, *)) { 17 | switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) { 18 | case AVAuthorizationStatusNotDetermined: 19 | return RNPermissionStatusNotDetermined; 20 | case AVAuthorizationStatusRestricted: 21 | return RNPermissionStatusRestricted; 22 | case AVAuthorizationStatusDenied: 23 | return RNPermissionStatusDenied; 24 | case AVAuthorizationStatusAuthorized: 25 | return RNPermissionStatusAuthorized; 26 | } 27 | } else { 28 | return RNPermissionStatusNotAvailable; 29 | } 30 | } 31 | 32 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 33 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 34 | if (@available(iOS 7.0, tvOS 17.0, *)) { 35 | [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo 36 | completionHandler:^(BOOL granted) { 37 | resolve(granted ? RNPermissionStatusAuthorized : [self currentStatus]); 38 | }]; 39 | } else { 40 | resolve([self currentStatus]); 41 | } 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /ios/Contacts/RNPermissionHandlerContacts.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerContacts : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Contacts/RNPermissionHandlerContacts.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerContacts.h" 2 | 3 | #if !TARGET_OS_TV 4 | #import 5 | #endif 6 | 7 | @implementation RNPermissionHandlerContacts 8 | 9 | + (NSArray * _Nonnull)usageDescriptionKeys { 10 | return @[@"NSContactsUsageDescription"]; 11 | } 12 | 13 | + (NSString * _Nonnull)handlerUniqueId { 14 | return @"ios.permission.CONTACTS"; 15 | } 16 | 17 | - (RNPermissionStatus)currentStatus { 18 | #if TARGET_OS_TV 19 | return RNPermissionStatusNotAvailable; 20 | #else 21 | switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) { 22 | case CNAuthorizationStatusNotDetermined: 23 | return RNPermissionStatusNotDetermined; 24 | case CNAuthorizationStatusRestricted: 25 | return RNPermissionStatusRestricted; 26 | case CNAuthorizationStatusDenied: 27 | return RNPermissionStatusDenied; 28 | case CNAuthorizationStatusLimited: 29 | return RNPermissionStatusLimited; 30 | case CNAuthorizationStatusAuthorized: 31 | return RNPermissionStatusAuthorized; 32 | } 33 | #endif 34 | } 35 | 36 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 37 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 38 | #if TARGET_OS_TV 39 | resolve(RNPermissionStatusNotAvailable); 40 | #else 41 | [[CNContactStore new] requestAccessForEntityType:CNEntityTypeContacts 42 | completionHandler:^(BOOL granted, NSError * _Nullable error) { 43 | if (error != nil && error.code != 100) { // error code 100 is permission denied 44 | reject(error); 45 | } else { 46 | resolve(granted ? RNPermissionStatusAuthorized : [self currentStatus]); 47 | } 48 | }]; 49 | #endif 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /ios/FaceID/RNPermissionHandlerFaceID.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerFaceID : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/FaceID/RNPermissionHandlerFaceID.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerFaceID.h" 2 | 3 | #import 4 | 5 | @interface RNPermissionHandlerFaceID() 6 | 7 | #if !TARGET_OS_TV 8 | @property (nonatomic, strong) LAContext *laContext; 9 | @property (nonatomic, strong) void (^resolve)(RNPermissionStatus status); 10 | #endif 11 | 12 | @end 13 | 14 | @implementation RNPermissionHandlerFaceID 15 | 16 | + (NSArray * _Nonnull)usageDescriptionKeys { 17 | return @[@"NSFaceIDUsageDescription"]; 18 | } 19 | 20 | + (NSString * _Nonnull)handlerUniqueId { 21 | return @"ios.permission.FACE_ID"; 22 | } 23 | 24 | - (RNPermissionStatus)currentStatus { 25 | #if TARGET_OS_TV 26 | return RNPermissionStatusNotAvailable; 27 | #else 28 | LAContext *context = [LAContext new]; 29 | NSError *error; 30 | 31 | [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]; 32 | bool hasFaceID = context.biometryType == LABiometryTypeFaceID; 33 | 34 | if (!hasFaceID) { 35 | return RNPermissionStatusNotAvailable; 36 | } 37 | 38 | if (error != nil) { 39 | if (error.code == LAErrorBiometryNotAvailable && hasFaceID) 40 | return RNPermissionStatusDenied; 41 | else 42 | return RNPermissionStatusNotAvailable; 43 | } 44 | 45 | if (![RNPermissions isFlaggedAsRequested:[[self class] handlerUniqueId]]) { 46 | return RNPermissionStatusNotDetermined; 47 | } 48 | 49 | return RNPermissionStatusAuthorized; 50 | #endif 51 | } 52 | 53 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 54 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 55 | #if TARGET_OS_TV 56 | resolve(RNPermissionStatusNotAvailable); 57 | #else 58 | LAContext *context = [LAContext new]; 59 | NSError *error; 60 | 61 | [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]; 62 | bool hasFaceID = context.biometryType == LABiometryTypeFaceID; 63 | 64 | if (!hasFaceID) { 65 | return resolve(RNPermissionStatusNotAvailable); 66 | } 67 | 68 | if (error != nil) { 69 | if (error.code == LAErrorBiometryNotAvailable && hasFaceID) 70 | return resolve(RNPermissionStatusDenied); 71 | else 72 | return resolve(RNPermissionStatusNotAvailable); 73 | } 74 | 75 | _resolve = resolve; 76 | _laContext = context; 77 | 78 | [[NSNotificationCenter defaultCenter] addObserver:self 79 | selector:@selector(onApplicationDidBecomeActive:) 80 | name:UIApplicationDidBecomeActiveNotification 81 | object:nil]; 82 | 83 | [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics 84 | localizedReason:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSFaceIDUsageDescription"] 85 | reply:^(__unused BOOL success, __unused NSError * _Nullable error) {}]; 86 | 87 | // Hack to invalidate FaceID verification immediately after being requested 88 | [self performSelector:@selector(invalidateContext) withObject:self afterDelay:0.05]; 89 | #endif 90 | } 91 | 92 | - (void)invalidateContext { 93 | #if !TARGET_OS_TV 94 | [_laContext invalidate]; 95 | #endif 96 | } 97 | 98 | - (void)onApplicationDidBecomeActive:(__unused NSNotification *)notification { 99 | [[NSNotificationCenter defaultCenter] removeObserver:self 100 | name:UIApplicationDidBecomeActiveNotification 101 | object:nil]; 102 | 103 | [RNPermissions flagAsRequested:[[self class] handlerUniqueId]]; 104 | 105 | #if !TARGET_OS_TV 106 | _resolve([self currentStatus]); 107 | #endif 108 | } 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /ios/LocationAccuracy/RNPermissionHandlerLocationAccuracy.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerLocationAccuracy : NSObject 4 | 5 | + (NSArray * _Nonnull)usageDescriptionKeys; 6 | 7 | + (NSString * _Nonnull)handlerUniqueId; 8 | 9 | - (void)checkWithResolver:(RCTPromiseResolveBlock _Nonnull)resolve 10 | rejecter:(RCTPromiseRejectBlock _Nonnull)reject; 11 | 12 | - (void)requestWithPurposeKey:(NSString * _Nonnull)purposeKey 13 | resolver:(RCTPromiseResolveBlock _Nonnull)resolve 14 | rejecter:(RCTPromiseRejectBlock _Nonnull)reject; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/LocationAccuracy/RNPermissionHandlerLocationAccuracy.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerLocationAccuracy.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerLocationAccuracy 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSLocationTemporaryUsageDescriptionDictionary"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.LOCATION_ACCURACY"; 13 | } 14 | 15 | - (void)checkWithResolver:(RCTPromiseResolveBlock _Nonnull)resolve 16 | rejecter:(RCTPromiseRejectBlock _Nonnull)reject { 17 | if (@available(iOS 14.0, tvOS 14.0, *)) { 18 | switch ([CLLocationManager authorizationStatus]) { 19 | case kCLAuthorizationStatusNotDetermined: 20 | return reject(@"cannot_check_location_accuracy", @"Location permission hasn't been requested first", nil); 21 | case kCLAuthorizationStatusRestricted: 22 | case kCLAuthorizationStatusDenied: 23 | return reject(@"cannot_check_location_accuracy", @"Location permission has been blocked by the user", nil); 24 | case kCLAuthorizationStatusAuthorizedWhenInUse: 25 | case kCLAuthorizationStatusAuthorizedAlways: 26 | break; 27 | } 28 | 29 | CLLocationManager *locationManager = [CLLocationManager new]; 30 | 31 | switch (locationManager.accuracyAuthorization) { 32 | case CLAccuracyAuthorizationFullAccuracy: 33 | return resolve(@"full"); 34 | case CLAccuracyAuthorizationReducedAccuracy: 35 | return resolve(@"reduced"); 36 | } 37 | } else { 38 | reject(@"cannot_check_location_accuracy", @"Only available on iOS 14 or higher", nil); 39 | } 40 | } 41 | 42 | - (void)requestWithPurposeKey:(NSString * _Nonnull)purposeKey 43 | resolver:(RCTPromiseResolveBlock _Nonnull)resolve 44 | rejecter:(RCTPromiseRejectBlock _Nonnull)reject { 45 | if (@available(iOS 14.0, tvOS 14.0, *)) { 46 | switch ([CLLocationManager authorizationStatus]) { 47 | case kCLAuthorizationStatusNotDetermined: 48 | return reject(@"cannot_request_location_accuracy", @"Location permission hasn't been requested first", nil); 49 | case kCLAuthorizationStatusRestricted: 50 | case kCLAuthorizationStatusDenied: 51 | return reject(@"cannot_request_location_accuracy", @"Location permission has been blocked by the user", nil); 52 | case kCLAuthorizationStatusAuthorizedWhenInUse: 53 | case kCLAuthorizationStatusAuthorizedAlways: 54 | break; 55 | } 56 | 57 | CLLocationManager *locationManager = [CLLocationManager new]; 58 | 59 | switch (locationManager.accuracyAuthorization) { 60 | case CLAccuracyAuthorizationFullAccuracy: 61 | return resolve(@"full"); // resolve early if full accuracy is already granted 62 | case CLAccuracyAuthorizationReducedAccuracy: 63 | break; 64 | } 65 | 66 | [locationManager requestTemporaryFullAccuracyAuthorizationWithPurposeKey:purposeKey 67 | completion:^(NSError * _Nullable error) { 68 | if (error) { 69 | reject([NSString stringWithFormat:@"%ld", (long)error.code], error.localizedDescription, error); 70 | } else { 71 | switch (locationManager.accuracyAuthorization) { 72 | case CLAccuracyAuthorizationFullAccuracy: 73 | return resolve(@"full"); 74 | case CLAccuracyAuthorizationReducedAccuracy: 75 | return resolve(@"reduced"); 76 | } 77 | } 78 | }]; 79 | } else { 80 | reject(@"cannot_request_location_accuracy", @"Only available on iOS 14 or higher", nil); 81 | } 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /ios/LocationAlways/RNPermissionHandlerLocationAlways.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerLocationAlways : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/LocationAlways/RNPermissionHandlerLocationAlways.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerLocationAlways.h" 2 | 3 | #import 4 | 5 | @interface RNPermissionHandlerLocationAlways() 6 | 7 | @property (nonatomic, assign) bool observingApplicationWillResignActive; 8 | @property (nonatomic, strong) CLLocationManager *locationManager; 9 | @property (nonatomic, strong) void (^resolve)(RNPermissionStatus status); 10 | 11 | @end 12 | 13 | @implementation RNPermissionHandlerLocationAlways 14 | 15 | + (NSArray * _Nonnull)usageDescriptionKeys { 16 | return @[@"NSLocationAlwaysAndWhenInUseUsageDescription"]; 17 | } 18 | 19 | + (NSString * _Nonnull)handlerUniqueId { 20 | return @"ios.permission.LOCATION_ALWAYS"; 21 | } 22 | 23 | - (RNPermissionStatus)currentStatus { 24 | #if TARGET_OS_TV 25 | return RNPermissionStatusNotAvailable; 26 | #else 27 | switch ([CLLocationManager authorizationStatus]) { 28 | case kCLAuthorizationStatusNotDetermined: 29 | return RNPermissionStatusNotDetermined; 30 | case kCLAuthorizationStatusRestricted: 31 | return RNPermissionStatusRestricted; 32 | case kCLAuthorizationStatusAuthorizedWhenInUse: 33 | case kCLAuthorizationStatusDenied: 34 | return RNPermissionStatusDenied; 35 | case kCLAuthorizationStatusAuthorizedAlways: 36 | return RNPermissionStatusAuthorized; 37 | } 38 | #endif 39 | } 40 | 41 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 42 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 43 | #if TARGET_OS_TV 44 | resolve(RNPermissionStatusNotAvailable); 45 | #else 46 | _resolve = resolve; 47 | 48 | if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) { 49 | [self performRequest]; 50 | } else { 51 | [[NSNotificationCenter defaultCenter] addObserver:self 52 | selector:@selector(performRequest) 53 | name:UIApplicationDidBecomeActiveNotification 54 | object:nil]; 55 | } 56 | #endif 57 | } 58 | 59 | - (void)performRequest { 60 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 61 | 62 | CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; 63 | 64 | if (status != kCLAuthorizationStatusNotDetermined && status != kCLAuthorizationStatusAuthorizedWhenInUse) { 65 | return _resolve([self currentStatus]); 66 | } 67 | 68 | _locationManager = [CLLocationManager new]; 69 | [_locationManager setDelegate:self]; 70 | 71 | if (status == kCLAuthorizationStatusAuthorizedWhenInUse) { 72 | [[NSNotificationCenter defaultCenter] addObserver:self 73 | selector:@selector(onApplicationWillResignActive) 74 | name:UIApplicationWillResignActiveNotification 75 | object:nil]; 76 | 77 | _observingApplicationWillResignActive = true; 78 | [self performSelector:@selector(onApplicationWillResignActiveCheck) withObject:nil afterDelay:0.25]; 79 | } 80 | 81 | [_locationManager requestAlwaysAuthorization]; 82 | } 83 | 84 | - (void)onApplicationWillResignActive { 85 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 86 | _observingApplicationWillResignActive = false; 87 | 88 | [[NSNotificationCenter defaultCenter] addObserver:self 89 | selector:@selector(onApplicationDidBecomeActive) 90 | name:UIApplicationDidBecomeActiveNotification 91 | object:nil]; 92 | } 93 | 94 | - (void)onApplicationWillResignActiveCheck { 95 | if (_observingApplicationWillResignActive) { 96 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 97 | _observingApplicationWillResignActive = false; 98 | 99 | [self resolveStatus:[CLLocationManager authorizationStatus]]; 100 | } 101 | } 102 | 103 | - (void)onApplicationDidBecomeActive { 104 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 105 | [self resolveStatus:[CLLocationManager authorizationStatus]]; 106 | } 107 | 108 | - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { 109 | if (status != kCLAuthorizationStatusNotDetermined && !_observingApplicationWillResignActive) { 110 | [self resolveStatus:status]; 111 | } 112 | } 113 | 114 | - (void)resolveStatus:(CLAuthorizationStatus)status { 115 | if (_resolve != nil) { 116 | _resolve([self currentStatus]); 117 | _resolve = nil; 118 | [_locationManager setDelegate:nil]; 119 | } 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /ios/LocationWhenInUse/RNPermissionHandlerLocationWhenInUse.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerLocationWhenInUse : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/LocationWhenInUse/RNPermissionHandlerLocationWhenInUse.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerLocationWhenInUse.h" 2 | 3 | #import 4 | 5 | @interface RNPermissionHandlerLocationWhenInUse() 6 | 7 | @property (nonatomic, strong) CLLocationManager *locationManager; 8 | @property (nonatomic, strong) void (^resolve)(RNPermissionStatus status); 9 | 10 | @end 11 | 12 | @implementation RNPermissionHandlerLocationWhenInUse 13 | 14 | + (NSArray * _Nonnull)usageDescriptionKeys { 15 | return @[@"NSLocationWhenInUseUsageDescription"]; 16 | } 17 | 18 | + (NSString * _Nonnull)handlerUniqueId { 19 | return @"ios.permission.LOCATION_WHEN_IN_USE"; 20 | } 21 | 22 | - (RNPermissionStatus)currentStatus { 23 | switch ([CLLocationManager authorizationStatus]) { 24 | case kCLAuthorizationStatusNotDetermined: 25 | return RNPermissionStatusNotDetermined; 26 | case kCLAuthorizationStatusRestricted: 27 | return RNPermissionStatusRestricted; 28 | case kCLAuthorizationStatusDenied: 29 | return RNPermissionStatusDenied; 30 | case kCLAuthorizationStatusAuthorizedWhenInUse: 31 | case kCLAuthorizationStatusAuthorizedAlways: 32 | return RNPermissionStatusAuthorized; 33 | } 34 | } 35 | 36 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 37 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 38 | if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusNotDetermined) { 39 | return resolve([self currentStatus]); 40 | } 41 | 42 | _resolve = resolve; 43 | 44 | _locationManager = [CLLocationManager new]; 45 | [_locationManager setDelegate:self]; 46 | [_locationManager requestWhenInUseAuthorization]; 47 | } 48 | 49 | - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { 50 | if (status != kCLAuthorizationStatusNotDetermined) { 51 | [_locationManager setDelegate:nil]; 52 | _resolve([self currentStatus]); 53 | } 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /ios/MediaLibrary/RNPermissionHandlerMediaLibrary.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerMediaLibrary : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/MediaLibrary/RNPermissionHandlerMediaLibrary.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerMediaLibrary.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerMediaLibrary 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSAppleMusicUsageDescription"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.MEDIA_LIBRARY"; 13 | } 14 | 15 | - (RNPermissionStatus)currentStatus { 16 | #if TARGET_OS_TV 17 | return RNPermissionStatusNotAvailable; 18 | #else 19 | switch ([MPMediaLibrary authorizationStatus]) { 20 | case MPMediaLibraryAuthorizationStatusNotDetermined: 21 | return RNPermissionStatusNotDetermined; 22 | case MPMediaLibraryAuthorizationStatusRestricted: 23 | return RNPermissionStatusRestricted; 24 | case MPMediaLibraryAuthorizationStatusDenied: 25 | return RNPermissionStatusDenied; 26 | case MPMediaLibraryAuthorizationStatusAuthorized: 27 | return RNPermissionStatusAuthorized; 28 | } 29 | #endif 30 | } 31 | 32 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 33 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 34 | #if TARGET_OS_TV 35 | resolve(RNPermissionStatusNotAvailable); 36 | #else 37 | [MPMediaLibrary requestAuthorization:^(__unused MPMediaLibraryAuthorizationStatus status) { 38 | resolve([self currentStatus]); 39 | }]; 40 | #endif 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /ios/Microphone/RNPermissionHandlerMicrophone.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerMicrophone : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Microphone/RNPermissionHandlerMicrophone.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerMicrophone.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerMicrophone 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSMicrophoneUsageDescription"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.MICROPHONE"; 13 | } 14 | 15 | - (RNPermissionStatus)currentStatus { 16 | if (@available(iOS 17.0, tvOS 17.0, *)) { 17 | switch ([[AVAudioApplication sharedInstance] recordPermission]) { 18 | case AVAudioApplicationRecordPermissionUndetermined: 19 | return RNPermissionStatusNotDetermined; 20 | case AVAudioApplicationRecordPermissionDenied: 21 | return RNPermissionStatusDenied; 22 | case AVAudioApplicationRecordPermissionGranted: 23 | return RNPermissionStatusAuthorized; 24 | } 25 | } else { 26 | #if TARGET_OS_TV 27 | return RNPermissionStatusNotAvailable; 28 | #else 29 | switch ([[AVAudioSession sharedInstance] recordPermission]) { 30 | case AVAudioSessionRecordPermissionUndetermined: 31 | return RNPermissionStatusNotDetermined; 32 | case AVAudioSessionRecordPermissionDenied: 33 | return RNPermissionStatusDenied; 34 | case AVAudioSessionRecordPermissionGranted: 35 | return RNPermissionStatusAuthorized; 36 | } 37 | #endif 38 | } 39 | } 40 | 41 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 42 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 43 | void (^completion)(BOOL) = ^(BOOL granted) { 44 | resolve(granted ? RNPermissionStatusAuthorized : [self currentStatus]); 45 | }; 46 | 47 | if (@available(iOS 17.0, tvOS 17.0, *)) { 48 | [AVAudioApplication requestRecordPermissionWithCompletionHandler:completion]; 49 | } else { 50 | #if TARGET_OS_TV 51 | resolve([self currentStatus]); 52 | #else 53 | [[AVAudioSession sharedInstance] requestRecordPermission:completion]; 54 | #endif 55 | } 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ios/Motion/RNPermissionHandlerMotion.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerMotion : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Motion/RNPermissionHandlerMotion.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerMotion.h" 2 | 3 | #if !TARGET_OS_TV 4 | #import 5 | #endif 6 | 7 | @interface RNPermissionHandlerMotion() 8 | 9 | #if !TARGET_OS_TV 10 | @property (nonatomic, strong) CMMotionActivityManager *activityManager; 11 | @property (nonatomic, strong) NSOperationQueue *operationQueue; 12 | #endif 13 | 14 | @end 15 | 16 | @implementation RNPermissionHandlerMotion 17 | 18 | + (NSArray * _Nonnull)usageDescriptionKeys { 19 | return @[@"NSMotionUsageDescription"]; 20 | } 21 | 22 | + (NSString * _Nonnull)handlerUniqueId { 23 | return @"ios.permission.MOTION"; 24 | } 25 | 26 | - (RNPermissionStatus)currentStatus { 27 | #if TARGET_OS_TV 28 | return RNPermissionStatusNotAvailable; 29 | #else 30 | if (![CMMotionActivityManager isActivityAvailable]) { 31 | return RNPermissionStatusNotAvailable; 32 | } 33 | 34 | switch ([CMMotionActivityManager authorizationStatus]) { 35 | case CMAuthorizationStatusNotDetermined: 36 | return RNPermissionStatusNotDetermined; 37 | case CMAuthorizationStatusRestricted: 38 | return RNPermissionStatusRestricted; 39 | case CMAuthorizationStatusDenied: 40 | return RNPermissionStatusDenied; 41 | case CMAuthorizationStatusAuthorized: 42 | return RNPermissionStatusAuthorized; 43 | } 44 | #endif 45 | } 46 | 47 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 48 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 49 | #if TARGET_OS_TV 50 | resolve(RNPermissionStatusNotAvailable); 51 | #else 52 | if (![CMMotionActivityManager isActivityAvailable]) { 53 | return resolve(RNPermissionStatusNotAvailable); 54 | } 55 | 56 | _activityManager = [CMMotionActivityManager new]; 57 | _operationQueue = [NSOperationQueue new]; 58 | _operationQueue.maxConcurrentOperationCount = 1; 59 | 60 | NSDate *now = [NSDate new]; 61 | 62 | [_activityManager queryActivityStartingFromDate:now 63 | toDate:now 64 | toQueue:_operationQueue 65 | withHandler:^(NSArray * _Nullable activities, NSError * _Nullable error) { 66 | if (error != nil && error.code != CMErrorNotAuthorized && error.code != CMErrorMotionActivityNotAuthorized) { 67 | return reject(error); 68 | } 69 | 70 | if (error != nil) { 71 | return resolve(RNPermissionStatusDenied); 72 | } 73 | if (activities) { 74 | return resolve(RNPermissionStatusAuthorized); 75 | } 76 | 77 | return resolve(RNPermissionStatusNotDetermined); 78 | }]; 79 | #endif 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /ios/Notifications/RNPermissionHandlerNotifications.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerNotifications : NSObject 4 | 5 | + (NSString * _Nonnull)handlerUniqueId; 6 | 7 | - (void)checkWithResolver:(void (^ _Nonnull)(RNPermissionStatus status, NSDictionary * _Nonnull settings))resolve; 8 | 9 | - (void)requestWithOptions:(NSArray * _Nonnull)options 10 | resolver:(void (^ _Nonnull)(RNPermissionStatus status, NSDictionary * _Nonnull settings))resolve 11 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull error))reject; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/Notifications/RNPermissionHandlerNotifications.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerNotifications.h" 2 | 3 | #import 4 | 5 | @interface RNPermissionHandlerNotifications() 6 | 7 | @property (nonatomic, strong) void (^resolve)(RNPermissionStatus status, NSDictionary * _Nonnull settings); 8 | @property (nonatomic, strong) void (^reject)(NSError *error); 9 | 10 | @end 11 | 12 | @implementation RNPermissionHandlerNotifications 13 | 14 | + (NSString * _Nonnull)handlerUniqueId { 15 | return @"ios.permission.NOTIFICATIONS"; 16 | } 17 | 18 | - (RNPermissionStatus)convertStatus:(UNAuthorizationStatus)status { 19 | switch (status) { 20 | case UNAuthorizationStatusNotDetermined: 21 | return RNPermissionStatusNotDetermined; 22 | case UNAuthorizationStatusDenied: 23 | return RNPermissionStatusDenied; 24 | #if !TARGET_OS_TV 25 | case UNAuthorizationStatusEphemeral: 26 | return RNPermissionStatusLimited; 27 | #endif 28 | case UNAuthorizationStatusAuthorized: 29 | case UNAuthorizationStatusProvisional: 30 | return RNPermissionStatusAuthorized; 31 | } 32 | } 33 | 34 | - (NSDictionary * _Nonnull)convertSettings:(UNNotificationSettings * _Nonnull)settings { 35 | NSMutableDictionary *result = [NSMutableDictionary new]; 36 | 37 | [result setValue:@(settings.authorizationStatus == UNAuthorizationStatusProvisional) forKey:@"provisional"]; 38 | 39 | if (settings.badgeSetting != UNNotificationSettingNotSupported) { 40 | [result setValue:@(settings.badgeSetting == UNNotificationSettingEnabled) forKey:@"badge"]; 41 | } 42 | 43 | #if !TARGET_OS_TV 44 | [result setValue:@(settings.providesAppNotificationSettings == true) forKey:@"providesAppSettings"]; 45 | 46 | if (settings.alertSetting != UNNotificationSettingNotSupported) { 47 | [result setValue:@(settings.alertSetting == UNNotificationSettingEnabled) forKey:@"alert"]; 48 | } 49 | if (settings.soundSetting != UNNotificationSettingNotSupported) { 50 | [result setValue:@(settings.soundSetting == UNNotificationSettingEnabled) forKey:@"sound"]; 51 | } 52 | if (settings.lockScreenSetting != UNNotificationSettingNotSupported) { 53 | [result setValue:@(settings.lockScreenSetting == UNNotificationSettingEnabled) forKey:@"lockScreen"]; 54 | } 55 | if (settings.carPlaySetting != UNNotificationSettingNotSupported) { 56 | [result setValue:@(settings.carPlaySetting == UNNotificationSettingEnabled) forKey:@"carPlay"]; 57 | } 58 | if (settings.notificationCenterSetting != UNNotificationSettingNotSupported) { 59 | [result setValue:@(settings.notificationCenterSetting == UNNotificationSettingEnabled) forKey:@"notificationCenter"]; 60 | } 61 | if (settings.criticalAlertSetting != UNNotificationSettingNotSupported) { 62 | [result setValue:@(settings.criticalAlertSetting == UNNotificationSettingEnabled) forKey:@"criticalAlert"]; 63 | } 64 | #endif 65 | 66 | return result; 67 | } 68 | 69 | - (void)checkWithResolver:(void (^ _Nonnull)(RNPermissionStatus status, NSDictionary * _Nonnull settings))resolve { 70 | [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { 71 | resolve([self convertStatus:settings.authorizationStatus], [self convertSettings:settings]); 72 | }]; 73 | } 74 | 75 | - (void)requestWithOptions:(NSArray * _Nonnull)options 76 | resolver:(void (^ _Nonnull)(RNPermissionStatus status, NSDictionary * _Nonnull settings))resolve 77 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull error))reject { 78 | bool alert = [options containsObject:@"alert"]; 79 | bool badge = [options containsObject:@"badge"]; 80 | bool sound = [options containsObject:@"sound"]; 81 | bool criticalAlert = [options containsObject:@"criticalAlert"]; 82 | bool carPlay = [options containsObject:@"carPlay"]; 83 | bool provisional = [options containsObject:@"provisional"]; 84 | bool providesAppSettings = [options containsObject:@"providesAppSettings"]; 85 | 86 | UNAuthorizationOptions types = UNAuthorizationOptionNone; 87 | 88 | if (alert) { 89 | types += UNAuthorizationOptionAlert; 90 | } 91 | if (badge) { 92 | types += UNAuthorizationOptionBadge; 93 | } 94 | if (sound) { 95 | types += UNAuthorizationOptionSound; 96 | } 97 | if (carPlay) { 98 | types += UNAuthorizationOptionCarPlay; 99 | } 100 | if (criticalAlert) { 101 | types += UNAuthorizationOptionCriticalAlert; 102 | } 103 | if (provisional) { 104 | types += UNAuthorizationOptionProvisional; 105 | } 106 | if (providesAppSettings) { 107 | types += UNAuthorizationOptionProvidesAppNotificationSettings; 108 | } 109 | 110 | if (!alert && 111 | !badge && 112 | !sound && 113 | !criticalAlert && 114 | !carPlay && 115 | !provisional && 116 | !providesAppSettings) { 117 | types += UNAuthorizationOptionAlert; 118 | types += UNAuthorizationOptionBadge; 119 | types += UNAuthorizationOptionSound; 120 | } 121 | 122 | [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:types 123 | completionHandler:^(BOOL granted, NSError * _Nullable error) { 124 | if (error != nil) { 125 | return reject(error); 126 | } 127 | 128 | if (granted) { 129 | dispatch_async(dispatch_get_main_queue(), ^{ 130 | [[UIApplication sharedApplication] registerForRemoteNotifications]; 131 | }); 132 | } 133 | 134 | [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { 135 | resolve([self convertStatus:settings.authorizationStatus], [self convertSettings:settings]); 136 | }]; 137 | }]; 138 | } 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /ios/PhotoLibrary/RNPermissionHandlerPhotoLibrary.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerPhotoLibrary : NSObject 4 | 5 | - (void)openPhotoPickerWithResolver:(RCTPromiseResolveBlock _Nonnull)resolve 6 | rejecter:(RCTPromiseRejectBlock _Nonnull)reject; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /ios/PhotoLibrary/RNPermissionHandlerPhotoLibrary.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerPhotoLibrary.h" 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | @implementation RNPermissionHandlerPhotoLibrary 8 | 9 | + (NSArray * _Nonnull)usageDescriptionKeys { 10 | return @[@"NSPhotoLibraryUsageDescription"]; 11 | } 12 | 13 | + (NSString * _Nonnull)handlerUniqueId { 14 | return @"ios.permission.PHOTO_LIBRARY"; 15 | } 16 | 17 | - (RNPermissionStatus)currentStatus { 18 | PHAuthorizationStatus status; 19 | 20 | if (@available(iOS 14.0, tvOS 14.0, *)) { 21 | status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; 22 | } else { 23 | status = [PHPhotoLibrary authorizationStatus]; 24 | } 25 | 26 | switch (status) { 27 | case PHAuthorizationStatusNotDetermined: 28 | return RNPermissionStatusNotDetermined; 29 | case PHAuthorizationStatusRestricted: 30 | return RNPermissionStatusRestricted; 31 | case PHAuthorizationStatusDenied: 32 | return RNPermissionStatusDenied; 33 | case PHAuthorizationStatusLimited: 34 | return RNPermissionStatusLimited; 35 | case PHAuthorizationStatusAuthorized: 36 | return RNPermissionStatusAuthorized; 37 | } 38 | } 39 | 40 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 41 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 42 | if (@available(iOS 14.0, tvOS 14.0, *)) { 43 | [PHPhotoLibrary requestAuthorizationForAccessLevel:PHAccessLevelReadWrite handler:^(__unused PHAuthorizationStatus status) { 44 | resolve([self currentStatus]); 45 | }]; 46 | } else { 47 | [PHPhotoLibrary requestAuthorization:^(__unused PHAuthorizationStatus status) { 48 | resolve([self currentStatus]); 49 | }]; 50 | } 51 | } 52 | 53 | - (void)openPhotoPickerWithResolver:(RCTPromiseResolveBlock _Nonnull)resolve 54 | rejecter:(RCTPromiseRejectBlock _Nonnull)reject { 55 | if (@available(iOS 14.0, tvOS 14.0, *)) { 56 | if ([PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite] != PHAuthorizationStatusLimited) { 57 | return reject(@"cannot_open_limited_picker", @"Photo library permission isn't limited", nil); 58 | } 59 | 60 | #if TARGET_OS_TV 61 | reject(@"cannot_open_limited_picker", @"Only available on iOS 14 or higher", nil); 62 | #else 63 | UIViewController *viewController = RCTPresentedViewController(); 64 | PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary]; 65 | 66 | if (@available(iOS 15.0, *)) { 67 | [photoLibrary presentLimitedLibraryPickerFromViewController:viewController 68 | completionHandler:^(__unused NSArray * _Nonnull assets) { 69 | resolve(@(true)); 70 | }]; 71 | } else { 72 | __block bool pickerVisible = false; 73 | [photoLibrary presentLimitedLibraryPickerFromViewController:viewController]; 74 | 75 | [NSTimer scheduledTimerWithTimeInterval:0.1 76 | repeats:true 77 | block:^(NSTimer * _Nonnull timer) { 78 | if ([RCTPresentedViewController() class] == [PHPickerViewController class]) { 79 | pickerVisible = true; 80 | } else if (pickerVisible) { 81 | [timer invalidate]; 82 | resolve(@(true)); 83 | } 84 | }]; 85 | } 86 | #endif 87 | } else { 88 | reject(@"cannot_open_limited_picker", @"Only available on iOS 14 or higher", nil); 89 | } 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /ios/PhotoLibraryAddOnly/RNPermissionHandlerPhotoLibraryAddOnly.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerPhotoLibraryAddOnly : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/PhotoLibraryAddOnly/RNPermissionHandlerPhotoLibraryAddOnly.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerPhotoLibraryAddOnly.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerPhotoLibraryAddOnly 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSPhotoLibraryAddUsageDescription"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.PHOTO_LIBRARY_ADD_ONLY"; 13 | } 14 | 15 | - (RNPermissionStatus)currentStatus { 16 | if (@available(iOS 14.0, tvOS 14.0, *)) { 17 | switch ([PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelAddOnly]) { 18 | case PHAuthorizationStatusNotDetermined: 19 | return RNPermissionStatusNotDetermined; 20 | case PHAuthorizationStatusRestricted: 21 | return RNPermissionStatusRestricted; 22 | case PHAuthorizationStatusDenied: 23 | return RNPermissionStatusDenied; 24 | case PHAuthorizationStatusLimited: 25 | return RNPermissionStatusLimited; 26 | case PHAuthorizationStatusAuthorized: 27 | return RNPermissionStatusAuthorized; 28 | } 29 | } else { 30 | return RNPermissionStatusNotAvailable; 31 | } 32 | } 33 | 34 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 35 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 36 | if (@available(iOS 14.0, tvOS 14.0, *)) { 37 | [PHPhotoLibrary requestAuthorizationForAccessLevel:PHAccessLevelAddOnly handler:^(__unused PHAuthorizationStatus status) { 38 | resolve([self currentStatus]); 39 | }]; 40 | } else { 41 | return resolve(RNPermissionStatusNotAvailable); 42 | } 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ios/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryUserDefaults 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | CA92.1 13 | 14 | 15 | 16 | NSPrivacyCollectedDataTypes 17 | 18 | NSPrivacyTracking 19 | 20 | NSPrivacyTrackingDomains 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ios/RNPermissions.h: -------------------------------------------------------------------------------- 1 | #ifdef RCT_NEW_ARCH_ENABLED 2 | #import 3 | #else 4 | #import 5 | #endif 6 | 7 | typedef enum { 8 | RNPermissionStatusNotAvailable = 0, 9 | RNPermissionStatusNotDetermined = 1, 10 | RNPermissionStatusRestricted = 2, 11 | RNPermissionStatusDenied = 3, 12 | RNPermissionStatusAuthorized = 4, 13 | RNPermissionStatusLimited = 5, 14 | } RNPermissionStatus; 15 | 16 | @protocol RNPermissionHandler 17 | 18 | @required 19 | 20 | + (NSArray * _Nonnull)usageDescriptionKeys; 21 | 22 | + (NSString * _Nonnull)handlerUniqueId; 23 | 24 | - (RNPermissionStatus)currentStatus; 25 | 26 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus status))resolve 27 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull error))reject; 28 | 29 | @end 30 | 31 | #ifdef RCT_NEW_ARCH_ENABLED 32 | @interface RNPermissions : NSObject 33 | #else 34 | @interface RNPermissions : NSObject 35 | #endif 36 | 37 | + (void)flagAsRequested:(NSString * _Nonnull)handlerId; 38 | 39 | + (bool)isFlaggedAsRequested:(NSString * _Nonnull)handlerId; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /ios/Reminders/RNPermissionHandlerReminders.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerReminders : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Reminders/RNPermissionHandlerReminders.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerReminders.h" 2 | 3 | #if !TARGET_OS_TV 4 | #import 5 | #endif 6 | 7 | @implementation RNPermissionHandlerReminders 8 | 9 | + (NSArray * _Nonnull)usageDescriptionKeys { 10 | return @[@"NSRemindersFullAccessUsageDescription"]; 11 | } 12 | 13 | + (NSString * _Nonnull)handlerUniqueId { 14 | return @"ios.permission.REMINDERS"; 15 | } 16 | 17 | - (RNPermissionStatus)currentStatus { 18 | #if TARGET_OS_TV 19 | return RNPermissionStatusNotAvailable; 20 | #else 21 | switch ([EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder]) { 22 | case EKAuthorizationStatusNotDetermined: 23 | return RNPermissionStatusNotDetermined; 24 | case EKAuthorizationStatusRestricted: 25 | return RNPermissionStatusRestricted; 26 | case EKAuthorizationStatusDenied: 27 | case EKAuthorizationStatusWriteOnly: 28 | return RNPermissionStatusDenied; 29 | case EKAuthorizationStatusFullAccess: 30 | return RNPermissionStatusAuthorized; 31 | } 32 | #endif 33 | } 34 | 35 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 36 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 37 | #if TARGET_OS_TV 38 | resolve(RNPermissionStatusNotAvailable); 39 | #else 40 | void (^completion)(BOOL, NSError * _Nullable) = ^(BOOL granted, NSError * _Nullable error) { 41 | if (error != nil) { 42 | reject(error); 43 | } else { 44 | resolve(granted ? RNPermissionStatusAuthorized : [self currentStatus]); 45 | } 46 | }; 47 | 48 | EKEventStore *store = [EKEventStore new]; 49 | 50 | if (@available(iOS 17.0, *)) { 51 | [store requestFullAccessToRemindersWithCompletion:completion]; 52 | } else { 53 | [store requestAccessToEntityType:EKEntityTypeReminder completion:completion]; 54 | } 55 | #endif 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ios/Siri/RNPermissionHandlerSiri.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerSiri : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Siri/RNPermissionHandlerSiri.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerSiri.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerSiri 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSSiriUsageDescription"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.SIRI"; 13 | } 14 | 15 | - (RNPermissionStatus)currentStatus { 16 | switch ([INPreferences siriAuthorizationStatus]) { 17 | case INSiriAuthorizationStatusNotDetermined: 18 | return RNPermissionStatusNotDetermined; 19 | case INSiriAuthorizationStatusRestricted: 20 | return RNPermissionStatusRestricted; 21 | case INSiriAuthorizationStatusDenied: 22 | return RNPermissionStatusDenied; 23 | case INSiriAuthorizationStatusAuthorized: 24 | return RNPermissionStatusAuthorized; 25 | } 26 | } 27 | 28 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 29 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 30 | [INPreferences requestSiriAuthorization:^(__unused INSiriAuthorizationStatus status) { 31 | resolve([self currentStatus]); 32 | }]; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /ios/SpeechRecognition/RNPermissionHandlerSpeechRecognition.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerSpeechRecognition : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/SpeechRecognition/RNPermissionHandlerSpeechRecognition.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerSpeechRecognition.h" 2 | 3 | #if !TARGET_OS_TV 4 | #import 5 | #endif 6 | 7 | @implementation RNPermissionHandlerSpeechRecognition 8 | 9 | + (NSArray * _Nonnull)usageDescriptionKeys { 10 | return @[@"NSSpeechRecognitionUsageDescription"]; 11 | } 12 | 13 | + (NSString * _Nonnull)handlerUniqueId { 14 | return @"ios.permission.SPEECH_RECOGNITION"; 15 | } 16 | 17 | - (RNPermissionStatus)currentStatus { 18 | #if TARGET_OS_TV 19 | return RNPermissionStatusNotAvailable; 20 | #else 21 | switch ([SFSpeechRecognizer authorizationStatus]) { 22 | case SFSpeechRecognizerAuthorizationStatusNotDetermined: 23 | return RNPermissionStatusNotDetermined; 24 | case SFSpeechRecognizerAuthorizationStatusRestricted: 25 | return RNPermissionStatusRestricted; 26 | case SFSpeechRecognizerAuthorizationStatusDenied: 27 | return RNPermissionStatusDenied; 28 | case SFSpeechRecognizerAuthorizationStatusAuthorized: 29 | return RNPermissionStatusAuthorized; 30 | } 31 | #endif 32 | } 33 | 34 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 35 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 36 | #if TARGET_OS_TV 37 | resolve(RNPermissionStatusNotAvailable); 38 | #else 39 | [SFSpeechRecognizer requestAuthorization:^(__unused SFSpeechRecognizerAuthorizationStatus status) { 40 | resolve([self currentStatus]); 41 | }]; 42 | #endif 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ios/StoreKit/RNPermissionHandlerStoreKit.h: -------------------------------------------------------------------------------- 1 | #import "RNPermissions.h" 2 | 3 | @interface RNPermissionHandlerStoreKit : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/StoreKit/RNPermissionHandlerStoreKit.mm: -------------------------------------------------------------------------------- 1 | #import "RNPermissionHandlerStoreKit.h" 2 | 3 | #import 4 | 5 | @implementation RNPermissionHandlerStoreKit 6 | 7 | + (NSArray * _Nonnull)usageDescriptionKeys { 8 | return @[@"NSAppleMusicUsageDescription"]; 9 | } 10 | 11 | + (NSString * _Nonnull)handlerUniqueId { 12 | return @"ios.permission.STOREKIT"; 13 | } 14 | 15 | - (RNPermissionStatus)currentStatus { 16 | #if TARGET_OS_SIMULATOR 17 | return RNPermissionStatusNotAvailable; 18 | #else 19 | switch ([SKCloudServiceController authorizationStatus]) { 20 | case SKCloudServiceAuthorizationStatusNotDetermined: 21 | return RNPermissionStatusNotDetermined; 22 | case SKCloudServiceAuthorizationStatusRestricted: 23 | return RNPermissionStatusRestricted; 24 | case SKCloudServiceAuthorizationStatusDenied: 25 | return RNPermissionStatusDenied; 26 | case SKCloudServiceAuthorizationStatusAuthorized: 27 | return RNPermissionStatusAuthorized; 28 | } 29 | #endif 30 | } 31 | 32 | - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve 33 | rejecter:(void (^ _Nonnull)(NSError * _Nonnull))reject { 34 | [SKCloudServiceController requestAuthorization:^(__unused SKCloudServiceAuthorizationStatus status) { 35 | resolve([self currentStatus]); 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /mock.js: -------------------------------------------------------------------------------- 1 | const { 2 | PERMISSIONS: {ANDROID}, 3 | } = require('./dist/commonjs/permissions.android'); 4 | const { 5 | PERMISSIONS: {IOS}, 6 | } = require('./dist/commonjs/permissions.ios'); 7 | const { 8 | PERMISSIONS: {WINDOWS}, 9 | } = require('./dist/commonjs/permissions.windows'); 10 | const {RESULTS} = require('./dist/commonjs/results'); 11 | 12 | const PERMISSIONS = {ANDROID, IOS, WINDOWS}; 13 | export {PERMISSIONS, RESULTS}; 14 | 15 | export const canScheduleExactAlarms = jest.fn(async () => true); 16 | export const canUseFullScreenIntent = jest.fn(async () => true); 17 | export const check = jest.fn(async () => RESULTS.GRANTED); 18 | export const checkLocationAccuracy = jest.fn(async () => 'full'); 19 | export const openPhotoPicker = jest.fn(async () => {}); 20 | export const openSettings = jest.fn(async () => {}); 21 | export const request = jest.fn(async () => RESULTS.GRANTED); 22 | export const requestLocationAccuracy = jest.fn(async () => 'full'); 23 | 24 | const notificationOptions = [ 25 | 'alert', 26 | 'badge', 27 | 'sound', 28 | 'carPlay', 29 | 'criticalAlert', 30 | 'provisional', 31 | 'providesAppSettings', 32 | ]; 33 | 34 | const notificationSettings = { 35 | alert: true, 36 | badge: true, 37 | sound: true, 38 | carPlay: true, 39 | criticalAlert: true, 40 | provisional: true, 41 | providesAppSettings: true, 42 | lockScreen: true, 43 | notificationCenter: true, 44 | }; 45 | 46 | export const checkNotifications = jest.fn(async () => ({ 47 | status: RESULTS.GRANTED, 48 | settings: notificationSettings, 49 | })); 50 | 51 | export const requestNotifications = jest.fn(async (options) => ({ 52 | status: RESULTS.GRANTED, 53 | settings: options 54 | .filter((option) => notificationOptions.includes(option)) 55 | .reduce((acc, option) => ({...acc, [option]: true}), { 56 | lockScreen: true, 57 | notificationCenter: true, 58 | }), 59 | })); 60 | 61 | export const checkMultiple = jest.fn(async (permissions) => 62 | permissions.reduce((acc, permission) => ({...acc, [permission]: RESULTS.GRANTED}), {}), 63 | ); 64 | 65 | export const requestMultiple = jest.fn(async (permissions) => 66 | permissions.reduce((acc, permission) => ({...acc, [permission]: RESULTS.GRANTED}), {}), 67 | ); 68 | 69 | export default { 70 | PERMISSIONS, 71 | RESULTS, 72 | 73 | canScheduleExactAlarms, 74 | canUseFullScreenIntent, 75 | check, 76 | checkLocationAccuracy, 77 | checkMultiple, 78 | checkNotifications, 79 | openPhotoPicker, 80 | openSettings, 81 | request, 82 | requestLocationAccuracy, 83 | requestMultiple, 84 | requestNotifications, 85 | }; 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-permissions", 3 | "version": "5.4.1", 4 | "license": "MIT", 5 | "description": "An unified permissions API for React Native on iOS, Android and Windows", 6 | "author": "Mathieu Acthernoene ", 7 | "homepage": "https://github.com/zoontek/react-native-permissions#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/zoontek/react-native-permissions.git" 11 | }, 12 | "keywords": [ 13 | "react-native", 14 | "react native", 15 | "react-native-windows", 16 | "permission", 17 | "authorization" 18 | ], 19 | "types": "dist/typescript/index.d.ts", 20 | "main": "dist/commonjs/index.js", 21 | "module": "dist/module/index.js", 22 | "react-native": "src/index.ts", 23 | "files": [ 24 | "/android", 25 | "!/android/build", 26 | "/dist", 27 | "/ios", 28 | "/scripts", 29 | "/windows", 30 | "/src", 31 | "/*.podspec", 32 | "app.plugin.js", 33 | "mock.js", 34 | "react-native.config.js" 35 | ], 36 | "scripts": { 37 | "clean": "rm -rf dist", 38 | "format": "prettier '**/*' -u -w", 39 | "lint": "eslint './**/*.{js,ts,tsx}'", 40 | "typecheck": "tsc --noEmit", 41 | "build": "yarn clean && bob build && rm -rf dist/*/package.json", 42 | "prepack": "prettier '**/*' -u -c && yarn lint && yarn typecheck && yarn build" 43 | }, 44 | "react-native-builder-bob": { 45 | "source": "src", 46 | "output": "dist", 47 | "targets": [ 48 | "commonjs", 49 | "module", 50 | "typescript" 51 | ] 52 | }, 53 | "codegenConfig": { 54 | "name": "RNPermissionsSpec", 55 | "type": "modules", 56 | "jsSrcsDir": "./src", 57 | "android": { 58 | "javaPackageName": "com.zoontek.rnpermissions" 59 | }, 60 | "windows": { 61 | "namespace": "RNPermissionsCodegen", 62 | "outputDirectory": "windows/RNPermissions/codegen", 63 | "separateDataTypes": true 64 | } 65 | }, 66 | "peerDependencies": { 67 | "react": ">=18.1.0", 68 | "react-native": ">=0.70.0", 69 | "react-native-windows": ">=0.70.0" 70 | }, 71 | "peerDependenciesMeta": { 72 | "react-native-windows": { 73 | "optional": true 74 | } 75 | }, 76 | "devDependencies": { 77 | "@babel/core": "^7.25.2", 78 | "@babel/preset-env": "^7.25.3", 79 | "@expo/config-plugins": "^7.0.0 || ^8.0.0 || ^9.0.0", 80 | "@types/react": "^19.0.0", 81 | "@typescript-eslint/eslint-plugin": "^8.30.1", 82 | "@typescript-eslint/parser": "^8.30.1", 83 | "eslint": "^8.57.1", 84 | "eslint-plugin-react": "^7.37.5", 85 | "eslint-plugin-react-hooks": "^4.6.2", 86 | "prettier": "^3.5.3", 87 | "prettier-plugin-organize-imports": "^4.1.0", 88 | "react": "19.0.0", 89 | "react-native": "0.78.2", 90 | "react-native-builder-bob": "^0.40.6", 91 | "react-native-windows": "0.78.4", 92 | "typescript": "^5.8.3" 93 | }, 94 | "react-native-windows": { 95 | "init-windows": { 96 | "name": "RNPermissions", 97 | "namespace": "RNPermissions", 98 | "template": "cpp-lib" 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /scripts/setup.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | def log_warning(message) 4 | puts "[Permissions] #{message}" 5 | end 6 | 7 | def setup_permissions(config) 8 | if config.nil? || !config.is_a?(Array) 9 | return log_warning("Invalid config argument") 10 | end 11 | 12 | permissions_frameworks = { 13 | 'AppTrackingTransparency' => ['AdSupport', 'AppTrackingTransparency'], 14 | 'Bluetooth' => ['CoreBluetooth'], 15 | 'Calendars' => ['EventKit'], 16 | 'CalendarsWriteOnly' => ['EventKit'], 17 | 'Camera' => ['AVFoundation'], 18 | 'Contacts' => ['Contacts'], 19 | 'FaceID' => ['LocalAuthentication'], 20 | 'LocationAccuracy' => ['CoreLocation'], 21 | 'LocationAlways' => ['CoreLocation'], 22 | 'LocationWhenInUse' => ['CoreLocation'], 23 | 'MediaLibrary' => ['MediaPlayer'], 24 | 'Microphone' => ['AVFoundation'], 25 | 'Motion' => ['CoreMotion'], 26 | 'Notifications' => ['UserNotifications'], 27 | 'PhotoLibrary' => ['Photos', 'PhotosUI'], 28 | 'PhotoLibraryAddOnly' => ['Photos'], 29 | 'Reminders' => ['EventKit'], 30 | 'Siri' => ['Intents'], 31 | 'SpeechRecognition' => ['Speech'], 32 | 'StoreKit' => ['StoreKit'] 33 | } 34 | 35 | module_dir = File.expand_path('..', __dir__) 36 | ios_dir = File.join(module_dir, 'ios') 37 | ios_dirents = Dir.entries(ios_dir).map { |entry| File.join(ios_dir, entry) } 38 | 39 | directories = ios_dirents 40 | .select { |entry| File.directory?(entry) || entry.end_with?('.xcodeproj') } 41 | .map { |entry| File.basename(entry) } 42 | .select { |name| config.include?(name) } 43 | 44 | unknown_permissions = config.reject { |name| directories.include?(name) } 45 | 46 | unless unknown_permissions.empty? 47 | log_warning("Unknown permissions: #{unknown_permissions.join(', ')}") 48 | end 49 | 50 | source_files = [ 51 | '"ios/*.{h,mm}"', 52 | *directories.map { |name| "\"ios/#{name}/*.{h,mm}\"" } 53 | ].join(', ') 54 | 55 | frameworks = directories 56 | .reduce([]) do |acc, dir| 57 | arr = permissions_frameworks[dir] 58 | arr ? acc.concat(arr) : acc 59 | end 60 | .map { |name| "\"#{name}\"" } 61 | .uniq 62 | .join(', ') 63 | 64 | podspec_path = File.join(module_dir, 'RNPermissions.podspec') 65 | podspec = File.read(podspec_path) 66 | 67 | podspec_content = podspec 68 | .gsub(/(# *)?s\.source_files *=.*/, "s.source_files = #{source_files}") 69 | .gsub(/(# *)?s\.frameworks *=.*/, "s.frameworks = #{frameworks}") 70 | 71 | File.write(podspec_path, podspec_content) 72 | end 73 | -------------------------------------------------------------------------------- /src/NativeRNPermissions.ts: -------------------------------------------------------------------------------- 1 | import type {TurboModule} from 'react-native'; 2 | import {TurboModuleRegistry} from 'react-native'; 3 | 4 | type NotificationsResponse = { 5 | status: Object; 6 | settings: Object; 7 | }; 8 | 9 | export interface Spec extends TurboModule { 10 | canScheduleExactAlarms(): Promise; 11 | canUseFullScreenIntent(): Promise; 12 | check(permission: string): Promise; 13 | checkLocationAccuracy(): Promise; 14 | checkMultiple(permissions: string[]): Promise; 15 | checkNotifications(): Promise; 16 | openPhotoPicker(): Promise; 17 | openSettings(type: string): Promise; 18 | request(permission: string): Promise; 19 | requestLocationAccuracy(purposeKey: string): Promise; 20 | requestMultiple(permissions: string[]): Promise; 21 | requestNotifications(options: string[]): Promise; 22 | shouldShowRequestRationale(permission: string): Promise; 23 | } 24 | 25 | export default TurboModuleRegistry.getEnforcing('RNPermissions'); 26 | -------------------------------------------------------------------------------- /src/contract.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | LocationAccuracy, 3 | LocationAccuracyOptions, 4 | NotificationOption, 5 | NotificationsResponse, 6 | Permission, 7 | PermissionStatus, 8 | Rationale, 9 | } from './types'; 10 | 11 | export type Contract = { 12 | canScheduleExactAlarms(): Promise; 13 | canUseFullScreenIntent(): Promise; 14 | check(permission: Permission): Promise; 15 | checkLocationAccuracy(): Promise; 16 | checkMultiple

( 17 | permissions: P, 18 | ): Promise>; 19 | checkNotifications(): Promise; 20 | openPhotoPicker(): Promise; 21 | openSettings(type?: 'application' | 'alarms' | 'fullscreen' | 'notifications'): Promise; 22 | request(permission: Permission, rationale?: Rationale): Promise; 23 | requestLocationAccuracy(options: LocationAccuracyOptions): Promise; 24 | requestMultiple

( 25 | permissions: P, 26 | ): Promise>; 27 | requestNotifications( 28 | options?: NotificationOption[], 29 | rationale?: Rationale, 30 | ): Promise; 31 | }; 32 | -------------------------------------------------------------------------------- /src/expo.ts: -------------------------------------------------------------------------------- 1 | import {type ConfigPlugin, createRunOncePlugin, withDangerousMod} from '@expo/config-plugins'; 2 | import {mergeContents} from '@expo/config-plugins/build/utils/generateCode'; 3 | import * as fs from 'fs/promises'; 4 | import * as path from 'path'; 5 | 6 | type Props = { 7 | iosPermissions?: ( 8 | | 'AppTrackingTransparency' 9 | | 'Bluetooth' 10 | | 'Calendars' 11 | | 'CalendarsWriteOnly' 12 | | 'Camera' 13 | | 'Contacts' 14 | | 'FaceID' 15 | | 'LocationAccuracy' 16 | | 'LocationAlways' 17 | | 'LocationWhenInUse' 18 | | 'MediaLibrary' 19 | | 'Microphone' 20 | | 'Motion' 21 | | 'Notifications' 22 | | 'PhotoLibrary' 23 | | 'PhotoLibraryAddOnly' 24 | | 'Reminders' 25 | | 'Siri' 26 | | 'SpeechRecognition' 27 | | 'StoreKit' 28 | )[]; 29 | }; 30 | 31 | const withPermissions: ConfigPlugin = (config, {iosPermissions = []}) => 32 | withDangerousMod(config, [ 33 | 'ios', 34 | async (config) => { 35 | const file = path.join(config.modRequest.platformProjectRoot, 'Podfile'); 36 | const contents = await fs.readFile(file, 'utf8'); 37 | 38 | if (iosPermissions.length === 0) { 39 | return config; 40 | } 41 | 42 | const withRequire = mergeContents({ 43 | tag: 'require', 44 | src: contents, 45 | anchor: 46 | /^require File\.join\(File\.dirname\(`node --print "require\.resolve\('react-native\/package\.json'\)"`\), "scripts\/react_native_pods"\)$/m, 47 | newSrc: `require File.join(File.dirname(\`node --print "require.resolve('react-native-permissions/package.json')"\`), "scripts/setup")`, 48 | offset: 1, 49 | comment: '#', 50 | }); 51 | 52 | const withSetup = mergeContents({ 53 | tag: 'setup', 54 | src: withRequire.contents, 55 | anchor: /^prepare_react_native_project!$/m, 56 | newSrc: `setup_permissions([ 57 | ${iosPermissions.map((permission) => ` '${permission}',`).join('\n')} 58 | ])`, 59 | offset: 1, 60 | comment: '#', 61 | }); 62 | 63 | await fs.writeFile(file, withSetup.contents, 'utf-8'); 64 | return config; 65 | }, 66 | ]); 67 | 68 | export default createRunOncePlugin(withPermissions, 'react-native-permissions'); 69 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import {methods} from './methods'; 2 | import {PERMISSIONS} from './permissions'; 3 | import {RESULTS} from './results'; 4 | 5 | export {PERMISSIONS} from './permissions'; 6 | export {RESULTS} from './results'; 7 | 8 | export * from './types'; 9 | 10 | export const canScheduleExactAlarms = methods.canScheduleExactAlarms; 11 | export const canUseFullScreenIntent = methods.canUseFullScreenIntent; 12 | export const check = methods.check; 13 | export const checkLocationAccuracy = methods.checkLocationAccuracy; 14 | export const checkMultiple = methods.checkMultiple; 15 | export const checkNotifications = methods.checkNotifications; 16 | export const openPhotoPicker = methods.openPhotoPicker; 17 | export const openSettings = methods.openSettings; 18 | export const request = methods.request; 19 | export const requestLocationAccuracy = methods.requestLocationAccuracy; 20 | export const requestMultiple = methods.requestMultiple; 21 | export const requestNotifications = methods.requestNotifications; 22 | 23 | export default { 24 | PERMISSIONS, 25 | RESULTS, 26 | 27 | canScheduleExactAlarms, 28 | canUseFullScreenIntent, 29 | check, 30 | checkLocationAccuracy, 31 | checkMultiple, 32 | checkNotifications, 33 | openPhotoPicker, 34 | openSettings, 35 | request, 36 | requestLocationAccuracy, 37 | requestMultiple, 38 | requestNotifications, 39 | }; 40 | -------------------------------------------------------------------------------- /src/methods.android.ts: -------------------------------------------------------------------------------- 1 | import {Alert, Platform} from 'react-native'; 2 | import NativeModule from './NativeRNPermissions'; 3 | import type {Contract} from './contract'; 4 | import type {NotificationsResponse, Permission, PermissionStatus, Rationale} from './types'; 5 | import { 6 | checkLocationAccuracy, 7 | openPhotoPicker, 8 | requestLocationAccuracy, 9 | } from './unsupportedMethods'; 10 | import {uniq} from './utils'; 11 | 12 | const POST_NOTIFICATIONS = 'android.permission.POST_NOTIFICATIONS' as Permission; 13 | const USES_LEGACY_NOTIFICATIONS = (Platform.OS === 'android' ? Platform.Version : 0) < 33; 14 | 15 | const shouldRequestPermission = async ( 16 | permission: Permission, 17 | rationale: Rationale | undefined, 18 | ): Promise => { 19 | if (rationale == null || !(await NativeModule.shouldShowRequestRationale(permission))) { 20 | return true; 21 | } 22 | 23 | if (typeof rationale === 'function') { 24 | return rationale(); 25 | } 26 | 27 | return new Promise((resolve) => { 28 | const {buttonNegative} = rationale; 29 | 30 | Alert.alert( 31 | rationale.title, 32 | rationale.message, 33 | [ 34 | ...(buttonNegative ? [{text: buttonNegative, onPress: () => resolve(false)}] : []), 35 | {text: rationale.buttonPositive, onPress: () => resolve(true)}, 36 | ], 37 | {cancelable: false}, 38 | ); 39 | }); 40 | }; 41 | 42 | const openSettings: Contract['openSettings'] = async (type = 'application') => { 43 | await NativeModule.openSettings(type); 44 | }; 45 | 46 | const canScheduleExactAlarms: Contract['canScheduleExactAlarms'] = () => 47 | NativeModule.canScheduleExactAlarms(); 48 | 49 | const canUseFullScreenIntent: Contract['canUseFullScreenIntent'] = () => 50 | NativeModule.canUseFullScreenIntent(); 51 | 52 | const check: Contract['check'] = async (permission) => { 53 | const status = (await NativeModule.check(permission)) as PermissionStatus; 54 | return status; 55 | }; 56 | 57 | const request: Contract['request'] = async (permission, rationale) => { 58 | const fn = (await shouldRequestPermission(permission, rationale)) 59 | ? NativeModule.request 60 | : NativeModule.check; 61 | 62 | const status = (await fn(permission)) as PermissionStatus; 63 | return status; 64 | }; 65 | 66 | const checkNotifications: Contract['checkNotifications'] = async () => { 67 | if (USES_LEGACY_NOTIFICATIONS) { 68 | const response = (await NativeModule.checkNotifications()) as NotificationsResponse; 69 | return response; 70 | } else { 71 | const status = await check(POST_NOTIFICATIONS); 72 | return {status, settings: {}}; 73 | } 74 | }; 75 | 76 | const requestNotifications: Contract['requestNotifications'] = async (options = [], rationale) => { 77 | if (USES_LEGACY_NOTIFICATIONS) { 78 | const response = (await NativeModule.requestNotifications(options)) as NotificationsResponse; 79 | return response; 80 | } else { 81 | const status = await request(POST_NOTIFICATIONS, rationale); 82 | return {status, settings: {}}; 83 | } 84 | }; 85 | 86 | const checkMultiple: Contract['checkMultiple'] = (permissions) => { 87 | return NativeModule.checkMultiple(uniq(permissions)) as ReturnType; 88 | }; 89 | 90 | const requestMultiple: Contract['requestMultiple'] = (permissions) => { 91 | return NativeModule.requestMultiple(uniq(permissions)) as ReturnType; 92 | }; 93 | 94 | export const methods: Contract = { 95 | canScheduleExactAlarms, 96 | canUseFullScreenIntent, 97 | check, 98 | checkLocationAccuracy, 99 | checkMultiple, 100 | checkNotifications, 101 | openPhotoPicker, 102 | openSettings, 103 | request, 104 | requestLocationAccuracy, 105 | requestMultiple, 106 | requestNotifications, 107 | }; 108 | -------------------------------------------------------------------------------- /src/methods.ios.ts: -------------------------------------------------------------------------------- 1 | import type {Contract} from './contract'; 2 | import NativeModule from './NativeRNPermissions'; 3 | import type {LocationAccuracy, NotificationsResponse, PermissionStatus} from './types'; 4 | import {canScheduleExactAlarms, canUseFullScreenIntent} from './unsupportedMethods'; 5 | import {uniq} from './utils'; 6 | 7 | const openPhotoPicker: Contract['openPhotoPicker'] = async () => { 8 | await NativeModule.openPhotoPicker(); 9 | }; 10 | 11 | const openSettings: Contract['openSettings'] = async (type = 'application') => { 12 | await NativeModule.openSettings(type); 13 | }; 14 | 15 | const check: Contract['check'] = async (permission) => { 16 | const status = (await NativeModule.check(permission)) as PermissionStatus; 17 | return status; 18 | }; 19 | 20 | const request: Contract['request'] = async (permission) => { 21 | const status = (await NativeModule.request(permission)) as PermissionStatus; 22 | return status; 23 | }; 24 | 25 | const checkLocationAccuracy: Contract['checkLocationAccuracy'] = async () => { 26 | const accuracy = (await NativeModule.checkLocationAccuracy()) as LocationAccuracy; 27 | return accuracy; 28 | }; 29 | 30 | const requestLocationAccuracy: Contract['requestLocationAccuracy'] = async ({purposeKey}) => { 31 | const accuracy = (await NativeModule.requestLocationAccuracy(purposeKey)) as LocationAccuracy; 32 | return accuracy; 33 | }; 34 | 35 | const checkNotifications: Contract['checkNotifications'] = async () => { 36 | const response = (await NativeModule.checkNotifications()) as NotificationsResponse; 37 | return response; 38 | }; 39 | 40 | const requestNotifications: Contract['requestNotifications'] = async ( 41 | options = ['alert', 'badge', 'sound'], 42 | ) => { 43 | const response = (await NativeModule.requestNotifications(options)) as NotificationsResponse; 44 | return response; 45 | }; 46 | 47 | const checkMultiple: Contract['checkMultiple'] = async (permissions) => { 48 | const output: Record = {}; 49 | 50 | for (const permission of uniq(permissions)) { 51 | output[permission] = await check(permission); 52 | } 53 | 54 | return output as Awaited>; 55 | }; 56 | 57 | const requestMultiple: Contract['requestMultiple'] = async (permissions) => { 58 | const output: Record = {}; 59 | 60 | for (const permission of uniq(permissions)) { 61 | output[permission] = await request(permission); 62 | } 63 | 64 | return output as Awaited>; 65 | }; 66 | 67 | export const methods: Contract = { 68 | canScheduleExactAlarms, 69 | canUseFullScreenIntent, 70 | check, 71 | checkLocationAccuracy, 72 | checkMultiple, 73 | checkNotifications, 74 | openPhotoPicker, 75 | openSettings, 76 | request, 77 | requestLocationAccuracy, 78 | requestMultiple, 79 | requestNotifications, 80 | }; 81 | -------------------------------------------------------------------------------- /src/methods.ts: -------------------------------------------------------------------------------- 1 | import type {Contract} from './contract'; 2 | import {RESULTS} from './results'; 3 | import type {PermissionStatus} from './types'; 4 | import { 5 | checkLocationAccuracy, 6 | openPhotoPicker, 7 | requestLocationAccuracy, 8 | } from './unsupportedMethods'; 9 | 10 | const check: Contract['check'] = async () => { 11 | return RESULTS.UNAVAILABLE; 12 | }; 13 | 14 | const checkNotifications: Contract['checkNotifications'] = async () => { 15 | return {status: RESULTS.UNAVAILABLE, settings: {}}; 16 | }; 17 | 18 | const checkMultiple: Contract['checkMultiple'] = async (permissions) => { 19 | const output: Record = {}; 20 | 21 | for (const permission of permissions) { 22 | output[permission] = RESULTS.UNAVAILABLE; 23 | } 24 | 25 | return output as Awaited>; 26 | }; 27 | 28 | export const methods: Contract = { 29 | canScheduleExactAlarms: Promise.reject, 30 | canUseFullScreenIntent: Promise.reject, 31 | check, 32 | checkLocationAccuracy, 33 | checkMultiple, 34 | checkNotifications, 35 | openPhotoPicker, 36 | openSettings: Promise.reject, 37 | request: check, 38 | requestLocationAccuracy, 39 | requestMultiple: checkMultiple, 40 | requestNotifications: checkNotifications, 41 | }; 42 | -------------------------------------------------------------------------------- /src/methods.windows.ts: -------------------------------------------------------------------------------- 1 | import NativeModule from './NativeRNPermissions'; 2 | import type {Contract} from './contract'; 3 | import type {NotificationsResponse, PermissionStatus} from './types'; 4 | import { 5 | canScheduleExactAlarms, 6 | canUseFullScreenIntent, 7 | checkLocationAccuracy, 8 | openPhotoPicker, 9 | requestLocationAccuracy, 10 | } from './unsupportedMethods'; 11 | import {uniq} from './utils'; 12 | 13 | const openSettings: Contract['openSettings'] = async () => { 14 | await NativeModule.openSettings('N/A'); 15 | }; 16 | 17 | const check: Contract['check'] = async (permission) => { 18 | const response = (await NativeModule.check(permission)) as PermissionStatus; 19 | return response; 20 | }; 21 | 22 | const request: Contract['request'] = async (permission) => { 23 | const response = (await NativeModule.request(permission)) as PermissionStatus; 24 | return response; 25 | }; 26 | 27 | const checkNotifications: Contract['checkNotifications'] = async () => { 28 | const response = (await NativeModule.checkNotifications()) as NotificationsResponse; 29 | return response; 30 | }; 31 | 32 | const checkMultiple: Contract['checkMultiple'] = async (permissions) => { 33 | const output: Record = {}; 34 | 35 | for (const permission of uniq(permissions)) { 36 | output[permission] = await check(permission); 37 | } 38 | 39 | return output as Awaited>; 40 | }; 41 | 42 | const requestMultiple: Contract['requestMultiple'] = async (permissions) => { 43 | const output: Record = {}; 44 | 45 | for (const permission of uniq(permissions)) { 46 | output[permission] = await request(permission); 47 | } 48 | 49 | return output as Awaited>; 50 | }; 51 | 52 | export const methods: Contract = { 53 | canScheduleExactAlarms, 54 | canUseFullScreenIntent, 55 | check, 56 | checkLocationAccuracy, 57 | checkMultiple, 58 | checkNotifications, 59 | openPhotoPicker, 60 | openSettings, 61 | request, 62 | requestLocationAccuracy, 63 | requestMultiple, 64 | requestNotifications: checkNotifications, 65 | }; 66 | -------------------------------------------------------------------------------- /src/permissions.android.ts: -------------------------------------------------------------------------------- 1 | import type {IOSPermissionMap} from './permissions.ios'; 2 | import type {WindowsPermissionMap} from './permissions.windows'; 3 | import {proxifyPermissions} from './utils'; 4 | 5 | const ANDROID = Object.freeze({ 6 | ACCEPT_HANDOVER: 'android.permission.ACCEPT_HANDOVER', 7 | ACCESS_BACKGROUND_LOCATION: 'android.permission.ACCESS_BACKGROUND_LOCATION', 8 | ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', 9 | ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', 10 | ACCESS_MEDIA_LOCATION: 'android.permission.ACCESS_MEDIA_LOCATION', 11 | ACTIVITY_RECOGNITION: 'android.permission.ACTIVITY_RECOGNITION', 12 | ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', 13 | ANSWER_PHONE_CALLS: 'android.permission.ANSWER_PHONE_CALLS', 14 | BLUETOOTH_ADVERTISE: 'android.permission.BLUETOOTH_ADVERTISE', 15 | BLUETOOTH_CONNECT: 'android.permission.BLUETOOTH_CONNECT', 16 | BLUETOOTH_SCAN: 'android.permission.BLUETOOTH_SCAN', 17 | BODY_SENSORS: 'android.permission.BODY_SENSORS', 18 | BODY_SENSORS_BACKGROUND: 'android.permission.BODY_SENSORS_BACKGROUND', 19 | CALL_PHONE: 'android.permission.CALL_PHONE', 20 | CAMERA: 'android.permission.CAMERA', 21 | GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', 22 | NEARBY_WIFI_DEVICES: 'android.permission.NEARBY_WIFI_DEVICES', 23 | PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', 24 | READ_CALENDAR: 'android.permission.READ_CALENDAR', 25 | READ_CALL_LOG: 'android.permission.READ_CALL_LOG', 26 | READ_CONTACTS: 'android.permission.READ_CONTACTS', 27 | READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', 28 | READ_MEDIA_AUDIO: 'android.permission.READ_MEDIA_AUDIO', 29 | READ_MEDIA_IMAGES: 'android.permission.READ_MEDIA_IMAGES', 30 | READ_MEDIA_VIDEO: 'android.permission.READ_MEDIA_VIDEO', 31 | READ_MEDIA_VISUAL_USER_SELECTED: 'android.permission.READ_MEDIA_VISUAL_USER_SELECTED', 32 | READ_PHONE_NUMBERS: 'android.permission.READ_PHONE_NUMBERS', 33 | READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', 34 | READ_SMS: 'android.permission.READ_SMS', 35 | RECEIVE_MMS: 'android.permission.RECEIVE_MMS', 36 | RECEIVE_SMS: 'android.permission.RECEIVE_SMS', 37 | RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', 38 | RECORD_AUDIO: 'android.permission.RECORD_AUDIO', 39 | SEND_SMS: 'android.permission.SEND_SMS', 40 | USE_SIP: 'android.permission.USE_SIP', 41 | UWB_RANGING: 'android.permission.UWB_RANGING', 42 | WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', 43 | WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', 44 | WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', 45 | WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', 46 | } as const); 47 | 48 | export type AndroidPermissionMap = typeof ANDROID; 49 | 50 | export const PERMISSIONS = Object.freeze({ 51 | ANDROID, 52 | IOS: proxifyPermissions('ios'), 53 | WINDOWS: proxifyPermissions('windows'), 54 | } as const); 55 | -------------------------------------------------------------------------------- /src/permissions.ios.ts: -------------------------------------------------------------------------------- 1 | import type {AndroidPermissionMap} from './permissions.android'; 2 | import type {WindowsPermissionMap} from './permissions.windows'; 3 | import {proxifyPermissions} from './utils'; 4 | 5 | const IOS = Object.freeze({ 6 | APP_TRACKING_TRANSPARENCY: 'ios.permission.APP_TRACKING_TRANSPARENCY', 7 | BLUETOOTH: 'ios.permission.BLUETOOTH', 8 | CALENDARS: 'ios.permission.CALENDARS', 9 | CALENDARS_WRITE_ONLY: 'ios.permission.CALENDARS_WRITE_ONLY', 10 | CAMERA: 'ios.permission.CAMERA', 11 | CONTACTS: 'ios.permission.CONTACTS', 12 | FACE_ID: 'ios.permission.FACE_ID', 13 | LOCATION_ALWAYS: 'ios.permission.LOCATION_ALWAYS', 14 | LOCATION_WHEN_IN_USE: 'ios.permission.LOCATION_WHEN_IN_USE', 15 | MEDIA_LIBRARY: 'ios.permission.MEDIA_LIBRARY', 16 | MICROPHONE: 'ios.permission.MICROPHONE', 17 | MOTION: 'ios.permission.MOTION', 18 | PHOTO_LIBRARY: 'ios.permission.PHOTO_LIBRARY', 19 | PHOTO_LIBRARY_ADD_ONLY: 'ios.permission.PHOTO_LIBRARY_ADD_ONLY', 20 | REMINDERS: 'ios.permission.REMINDERS', 21 | SIRI: 'ios.permission.SIRI', 22 | SPEECH_RECOGNITION: 'ios.permission.SPEECH_RECOGNITION', 23 | STOREKIT: 'ios.permission.STOREKIT', 24 | } as const); 25 | 26 | export type IOSPermissionMap = typeof IOS; 27 | 28 | export const PERMISSIONS = Object.freeze({ 29 | ANDROID: proxifyPermissions('android'), 30 | IOS, 31 | WINDOWS: proxifyPermissions('windows'), 32 | } as const); 33 | -------------------------------------------------------------------------------- /src/permissions.ts: -------------------------------------------------------------------------------- 1 | import type {AndroidPermissionMap} from './permissions.android'; 2 | import type {IOSPermissionMap} from './permissions.ios'; 3 | import type {WindowsPermissionMap} from './permissions.windows'; 4 | import {proxifyPermissions} from './utils'; 5 | 6 | export const PERMISSIONS = Object.freeze({ 7 | ANDROID: proxifyPermissions('android'), 8 | IOS: proxifyPermissions('ios'), 9 | WINDOWS: proxifyPermissions('windows'), 10 | } as const); 11 | -------------------------------------------------------------------------------- /src/results.ts: -------------------------------------------------------------------------------- 1 | export const RESULTS = Object.freeze({ 2 | UNAVAILABLE: 'unavailable', 3 | BLOCKED: 'blocked', 4 | DENIED: 'denied', 5 | GRANTED: 'granted', 6 | LIMITED: 'limited', 7 | } as const); 8 | 9 | export type ResultMap = typeof RESULTS; 10 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type {AndroidPermissionMap} from './permissions.android'; 2 | import type {IOSPermissionMap} from './permissions.ios'; 3 | import type {WindowsPermissionMap} from './permissions.windows'; 4 | import type {ResultMap} from './results'; 5 | 6 | type ValueOf = T[keyof T]; 7 | 8 | export type AndroidPermission = ValueOf; 9 | export type IOSPermission = ValueOf; 10 | export type WindowsPermission = ValueOf; 11 | export type Permission = AndroidPermission | IOSPermission | WindowsPermission; 12 | export type PermissionStatus = ValueOf; 13 | 14 | export type RationaleObject = { 15 | title: string; 16 | message: string; 17 | buttonPositive: string; 18 | buttonNegative?: string; 19 | }; 20 | 21 | export type Rationale = RationaleObject | (() => Promise); 22 | 23 | export type LocationAccuracy = 'full' | 'reduced'; 24 | export type LocationAccuracyOptions = {purposeKey: string}; 25 | 26 | export type NotificationOption = 27 | | 'alert' 28 | | 'badge' 29 | | 'sound' 30 | | 'carPlay' 31 | | 'criticalAlert' 32 | | 'provisional' 33 | | 'providesAppSettings'; 34 | 35 | export type NotificationSettings = { 36 | alert?: boolean; 37 | badge?: boolean; 38 | sound?: boolean; 39 | carPlay?: boolean; 40 | criticalAlert?: boolean; 41 | provisional?: boolean; 42 | providesAppSettings?: boolean; 43 | lockScreen?: boolean; 44 | notificationCenter?: boolean; 45 | }; 46 | 47 | export type NotificationsResponse = { 48 | status: PermissionStatus; 49 | settings: NotificationSettings; 50 | }; 51 | -------------------------------------------------------------------------------- /src/unsupportedMethods.ts: -------------------------------------------------------------------------------- 1 | import type {Contract} from './contract'; 2 | 3 | const getUnsupportedError = (os: 'iOS' | 'Android', version: number) => 4 | new Error(`Only supported by ${os} ${version} and above`); 5 | 6 | export const canScheduleExactAlarms: Contract['canScheduleExactAlarms'] = async () => { 7 | throw getUnsupportedError('Android', 12); 8 | }; 9 | 10 | export const canUseFullScreenIntent: Contract['canUseFullScreenIntent'] = async () => { 11 | throw getUnsupportedError('Android', 14); 12 | }; 13 | 14 | export const openPhotoPicker: Contract['openPhotoPicker'] = async () => { 15 | throw getUnsupportedError('iOS', 14); 16 | }; 17 | 18 | export const requestLocationAccuracy: Contract['requestLocationAccuracy'] = async () => { 19 | throw getUnsupportedError('iOS', 14); 20 | }; 21 | 22 | export const checkLocationAccuracy: Contract['checkLocationAccuracy'] = async () => { 23 | throw getUnsupportedError('iOS', 14); 24 | }; 25 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export const proxifyPermissions = >( 2 | platform: 'android' | 'ios' | 'windows', 3 | ) => 4 | new Proxy({} as T, { 5 | get: (_, prop) => (typeof prop === 'string' ? `${platform}.permission.${prop}` : prop), 6 | }); 7 | 8 | export const uniq = (array: T[]): T[] => { 9 | return array.filter((item, index) => item != null && array.indexOf(item) === index); 10 | }; 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "lib": ["ES2017"], 5 | "jsx": "react-native", 6 | "moduleResolution": "Node", 7 | 8 | "allowJs": false, 9 | "strict": true, 10 | "declaration": true, 11 | "sourceMap": true, 12 | "stripInternal": true, 13 | "skipLibCheck": true, 14 | "verbatimModuleSyntax": true, 15 | 16 | "allowUnreachableCode": false, 17 | "allowUnusedLabels": false, 18 | "noFallthroughCasesInSwitch": true, 19 | "noImplicitOverride": true, 20 | "noImplicitReturns": false, 21 | "noUncheckedIndexedAccess": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true 24 | }, 25 | "include": ["src"], 26 | "exclude": ["example", "node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | *AppPackages* 2 | *BundleArtifacts* 3 | 4 | #OS junk files 5 | [Tt]humbs.db 6 | *.DS_Store 7 | 8 | #Visual Studio files 9 | *.[Oo]bj 10 | *.user 11 | *.aps 12 | *.pch 13 | *.vspscc 14 | *.vssscc 15 | *_i.c 16 | *_p.c 17 | *.ncb 18 | *.suo 19 | *.tlb 20 | *.tlh 21 | *.bak 22 | *.[Cc]ache 23 | *.ilk 24 | *.log 25 | *.lib 26 | *.sbr 27 | *.sdf 28 | *.opensdf 29 | *.opendb 30 | *.unsuccessfulbuild 31 | ipch/ 32 | [Oo]bj/ 33 | [Bb]in 34 | [Dd]ebug*/ 35 | [Rr]elease*/ 36 | Ankh.NoLoad 37 | .vs/ 38 | # Visual C++ cache files 39 | 40 | #Files generated by the VS build 41 | **/Generated Files/** 42 | -------------------------------------------------------------------------------- /windows/ExperimentalFeatures.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | true 16 | 17 | 28 | true 29 | 30 | true 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /windows/RNPermissions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32929.385 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNPermissions", "RNPermissions\RNPermissions.vcxproj", "{99677B9D-A27B-4239-930E-C36C8D339C54}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Debug|ARM64 = Debug|ARM64 13 | Release|x64 = Release|x64 14 | Release|x86 = Release|x86 15 | Release|ARM64 = Release|ARM64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x64.ActiveCfg = Debug|x64 19 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x64.Build.0 = Debug|x64 20 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x64.Deploy.0 = Debug|x64 21 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x86.ActiveCfg = Debug|Win32 22 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x86.Build.0 = Debug|Win32 23 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|x86.Deploy.0 = Debug|Win32 24 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|ARM64.ActiveCfg = Debug|ARM64 25 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|ARM64.Build.0 = Debug|ARM64 26 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Debug|ARM64.Deploy.0 = Debug|ARM64 27 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x64.ActiveCfg = Release|x64 28 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x64.Build.0 = Release|x64 29 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x64.Deploy.0 = Release|x64 30 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x86.ActiveCfg = Release|Win32 31 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x86.Build.0 = Release|Win32 32 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|x86.Deploy.0 = Release|Win32 33 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|ARM64.ActiveCfg = Release|ARM64 34 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|ARM64.Build.0 = Release|ARM64 35 | {99677B9D-A27B-4239-930E-C36C8D339C54}.Release|ARM64.Deploy.0 = Release|ARM64 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /windows/RNPermissions/PropertySheet.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /windows/RNPermissions/RNPermissions.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE 3 | DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE 4 | -------------------------------------------------------------------------------- /windows/RNPermissions/RNPermissions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pch.h" 4 | #include "resource.h" 5 | 6 | #include 7 | 8 | #include "codegen/NativeRnPermissionsDataTypes.g.h" 9 | #include "codegen/NativeRnPermissionsSpec.g.h" 10 | 11 | using namespace RNPermissionsCodegen; 12 | namespace winrt::RNPermissions 13 | { 14 | 15 | REACT_MODULE(RNPermissions) 16 | struct RNPermissions 17 | { 18 | using ModuleSpec = RNPermissionsCodegen::RNPermissionsSpec; 19 | 20 | REACT_INIT(Initialize); 21 | void Initialize(React::ReactContext const& reactContext) noexcept; 22 | 23 | REACT_METHOD(OpenSettings, L"openSettings"); 24 | void OpenSettings(std::wstring type, React::ReactPromise&& promise) noexcept; 25 | 26 | REACT_METHOD(OpenPhotoPicker, L"openPhotoPicker"); 27 | void OpenPhotoPicker(React::ReactPromise&& promise) noexcept; 28 | 29 | REACT_METHOD(CanScheduleExactAlarms, L"canScheduleExactAlarms"); 30 | void CanScheduleExactAlarms(React::ReactPromise&& promise) noexcept; 31 | 32 | REACT_METHOD(CanUseFullScreenIntent, L"canUseFullScreenIntent"); 33 | void CanUseFullScreenIntent(React::ReactPromise&& promise) noexcept; 34 | 35 | REACT_METHOD(CheckLocationAccuracy, L"checkLocationAccuracy"); 36 | void CheckLocationAccuracy(React::ReactPromise&& promise) noexcept; 37 | 38 | REACT_METHOD(CheckNotifications, L"checkNotifications"); 39 | void CheckNotifications(React::ReactPromise&& promise) noexcept; 40 | 41 | REACT_METHOD(Check, L"check"); 42 | void Check(std::wstring permission, React::ReactPromise&& promise) noexcept; 43 | 44 | REACT_METHOD(CheckMultiple, L"checkMultiple"); 45 | void CheckMultiple(std::vector permissions, React::ReactPromise<::React::JSValue>&& promise) noexcept; 46 | 47 | REACT_METHOD(Request, L"request"); 48 | void Request(std::wstring permission, React::ReactPromise&& promise) noexcept; 49 | 50 | REACT_METHOD(RequestMultiple, L"requestMultiple"); 51 | void RequestMultiple(std::vector permissions, React::ReactPromise<::React::JSValue>&& promise) noexcept; 52 | 53 | REACT_METHOD(RequestNotifications, L"requestNotifications"); 54 | void RequestNotifications(std::vector options, React::ReactPromise&& promise) noexcept; 55 | 56 | REACT_METHOD(RequestLocationAccuracy, L"requestLocationAccuracy"); 57 | void RequestLocationAccuracy(std::wstring purposeKey, React::ReactPromise&& promise) noexcept; 58 | 59 | REACT_METHOD(ShouldShowRequestRationale, L"shouldShowRequestRationale"); 60 | void ShouldShowRequestRationale(std::wstring permission, React::ReactPromise&& promise) noexcept; 61 | 62 | private: 63 | React::ReactContext m_context; 64 | }; 65 | 66 | } // namespace winrt::RNPermissions 67 | -------------------------------------------------------------------------------- /windows/RNPermissions/RNPermissions.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoontek/react-native-permissions/88e29dbd53da1cfe5022265b05c5519a5c8bb540/windows/RNPermissions/RNPermissions.rc -------------------------------------------------------------------------------- /windows/RNPermissions/RNPermissions.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | 40 | 41 | Resource Files 42 | 43 | 44 | -------------------------------------------------------------------------------- /windows/RNPermissions/ReactPackageProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "ReactPackageProvider.h" 4 | #if __has_include("ReactPackageProvider.g.cpp") 5 | #include "ReactPackageProvider.g.cpp" 6 | #endif 7 | 8 | #include "RNPermissions.h" 9 | 10 | using namespace winrt::Microsoft::ReactNative; 11 | 12 | namespace winrt::RNPermissions::implementation 13 | { 14 | 15 | void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept 16 | { 17 | #ifdef RnwNewArch 18 | AddAttributedModules(packageBuilder, true); 19 | #else 20 | AddAttributedModules(packageBuilder); 21 | #endif 22 | } 23 | 24 | } // namespace winrt::RNPermissions::implementation 25 | -------------------------------------------------------------------------------- /windows/RNPermissions/ReactPackageProvider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ReactPackageProvider.g.h" 4 | 5 | using namespace winrt::Microsoft::ReactNative; 6 | 7 | namespace winrt::RNPermissions::implementation 8 | { 9 | 10 | struct ReactPackageProvider : ReactPackageProviderT 11 | { 12 | ReactPackageProvider() = default; 13 | 14 | void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept; 15 | }; 16 | 17 | } // namespace winrt::RNPermissions::implementation 18 | 19 | namespace winrt::RNPermissions::factory_implementation 20 | { 21 | 22 | struct ReactPackageProvider : ReactPackageProviderT {}; 23 | 24 | } // namespace winrt::RNPermissions::factory_implementation 25 | -------------------------------------------------------------------------------- /windows/RNPermissions/ReactPackageProvider.idl: -------------------------------------------------------------------------------- 1 | namespace RNPermissions 2 | { 3 | [webhosthidden] 4 | [default_interface] 5 | runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider 6 | { 7 | ReactPackageProvider(); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /windows/RNPermissions/codegen/.clang-format: -------------------------------------------------------------------------------- 1 | DisableFormat: true 2 | SortIncludes: false 3 | -------------------------------------------------------------------------------- /windows/RNPermissions/codegen/NativeRNPermissionsDataTypes.g.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file is auto-generated from a NativeModule spec file in js. 4 | * 5 | * This is a C++ Spec class that should be used with MakeTurboModuleProvider to register native modules 6 | * in a way that also verifies at compile time that the native module matches the interface required 7 | * by the TurboModule JS spec. 8 | */ 9 | #pragma once 10 | // clang-format off 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace RNPermissionsCodegen { 18 | 19 | struct RNPermissionsSpec_NotificationsResponse { 20 | ::React::JSValue status; 21 | ::React::JSValue settings; 22 | }; 23 | 24 | } // namespace RNPermissionsCodegen 25 | -------------------------------------------------------------------------------- /windows/RNPermissions/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /windows/RNPermissions/packages.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": { 4 | "native,Version=v0.0": { 5 | "boost": { 6 | "type": "Direct", 7 | "requested": "[1.83.0, )", 8 | "resolved": "1.83.0", 9 | "contentHash": "cy53VNMzysEMvhBixDe8ujPk67Fcj3v6FPHQnH91NYJNLHpc6jxa2xq9ruCaaJjE4M3YrGSHDi4uUSTGBWw6EQ==" 10 | }, 11 | "Microsoft.ReactNative": { 12 | "type": "Direct", 13 | "requested": "[0.77.2-Fabric, )", 14 | "resolved": "0.77.2-Fabric", 15 | "contentHash": "tE/bhrg3qoxQoJofScQWP8fx/xnbdmo0DuLAjNkSv3gy9RNpEQdMAzlUHo5+3lJcPGJ4wAzlue2Nsdb0YJQ2Lw==" 16 | }, 17 | "Microsoft.ReactNative.Cxx": { 18 | "type": "Direct", 19 | "requested": "[0.77.2-Fabric, )", 20 | "resolved": "0.77.2-Fabric", 21 | "contentHash": "Xc20uZX79+pK7uiqlrd9jVMTqMkC5KgWTLs9poZa9Q+xKbObmIVD17kLFZ2hwvWgVwhVhI+jVRXAAoyNNJBw+Q==", 22 | "dependencies": { 23 | "Microsoft.ReactNative": "0.77.2-Fabric" 24 | } 25 | }, 26 | "Microsoft.VCRTForwarders.140": { 27 | "type": "Direct", 28 | "requested": "[1.0.2-rc, )", 29 | "resolved": "1.0.2-rc", 30 | "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" 31 | }, 32 | "Microsoft.Windows.CppWinRT": { 33 | "type": "Direct", 34 | "requested": "[2.0.230706.1, )", 35 | "resolved": "2.0.230706.1", 36 | "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ==" 37 | }, 38 | "Microsoft.WindowsAppSDK": { 39 | "type": "Direct", 40 | "requested": "[1.6.240923002, )", 41 | "resolved": "1.6.240923002", 42 | "contentHash": "7PfOz2scXU+AAM/GYge+f6s7k3DVI+R1P8MNPZQr56GOPCGw+csvcg3S5KZg47z/o04kNvWH3GKtWT1ML9tpZw==", 43 | "dependencies": { 44 | "Microsoft.Web.WebView2": "1.0.2651.64", 45 | "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756" 46 | } 47 | }, 48 | "Microsoft.Web.WebView2": { 49 | "type": "Transitive", 50 | "resolved": "1.0.2651.64", 51 | "contentHash": "f5sc/vcAoTCTEW7Nqzp4galAuTRguZViw8ksn+Nx2uskEBPm0/ubzy6gVjvXS/P96jLS89C8T9I0hPc417xpNg==" 52 | }, 53 | "Microsoft.Windows.SDK.BuildTools": { 54 | "type": "Transitive", 55 | "resolved": "10.0.22621.756", 56 | "contentHash": "7ZL2sFSioYm1Ry067Kw1hg0SCcW5kuVezC2SwjGbcPE61Nn+gTbH86T73G3LcEOVj0S3IZzNuE/29gZvOLS7VA==" 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /windows/RNPermissions/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /windows/RNPermissions/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define NOMINMAX 1 11 | #define WIN32_LEAN_AND_MEAN 1 12 | #define WINRT_LEAN_AND_MEAN 1 13 | 14 | // Windows Header Files 15 | #include 16 | #undef GetCurrentTime 17 | #include 18 | 19 | // WinRT Header Files 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | // C RunTime Header Files 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | // Reference additional headers your project requires here 40 | -------------------------------------------------------------------------------- /windows/RNPermissions/resource.h: -------------------------------------------------------------------------------- 1 | // 2 | // Microsoft Visual C++ generated include file. 3 | // Used by RNPermissions.rc 4 | 5 | #pragma once 6 | -------------------------------------------------------------------------------- /windows/RNPermissions/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | --------------------------------------------------------------------------------