├── .circleci └── config.yml ├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ ├── build-android.yml │ ├── build-ios.yml │ ├── first-issue-or-pr.yml │ ├── publishnpm.yml │ ├── sponsor.yml │ ├── stale-bot.yml │ ├── validate-android.yml │ └── validate-js.yml ├── .gitignore ├── .yarn └── install-state.gz ├── .yarnrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── android ├── CMakeLists.txt ├── RNKeys.gradle ├── androidcpp │ ├── json.hpp │ └── mediator.cpp ├── build.gradle ├── cpp-adapter.cpp ├── gradle.properties └── src │ ├── main │ ├── AndroidManifest.xml │ ├── AndroidManifestDeprecated.xml │ └── java │ │ └── com │ │ └── reactnativekeysjsi │ │ ├── KeysModule.java │ │ ├── KeysPackage.java │ │ └── PrivateKey.java │ ├── newarch │ └── KeysSpec.java │ └── oldarch │ └── KeysSpec.java ├── app.plugin.js ├── babel.config.js ├── cpp ├── crypto.cpp ├── crypto.h ├── decryptor.cpp └── decryptor.h ├── docs ├── react-native-config-migration-guide.md └── workflow.md ├── example ├── .bundle │ └── config ├── .watchmanconfig ├── Gemfile ├── README.md ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── keysexample │ │ │ │ └── ReactNativeFlipper.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── keysexample │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ └── 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 │ │ │ └── release │ │ │ └── java │ │ │ └── com │ │ │ └── keysexample │ │ │ └── ReactNativeFlipper.java │ ├── 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 │ ├── Config.xcconfig │ ├── KeysExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── KeysExample-Dev.xcscheme │ │ │ ├── KeysExample-Production.xcscheme │ │ │ └── KeysExample-Staging.xcscheme │ ├── KeysExample.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── KeysExample │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── main.m │ ├── KeysExampleTests │ │ ├── Info.plist │ │ └── KeysExampleTests.m │ ├── Podfile │ └── Podfile.lock ├── jest.config.js ├── keys.development.json ├── keys.production.json ├── keys.staging.json ├── metro.config.js ├── package.json ├── react-native.config.js ├── src │ └── App.tsx └── yarn.lock ├── exampleExpo ├── App.js ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── keys │ │ │ │ └── development │ │ │ │ └── ReactNativeFlipper.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── keys │ │ │ │ │ └── development │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ │ ├── drawable-hdpi │ │ │ │ └── splashscreen_image.png │ │ │ │ ├── drawable-mdpi │ │ │ │ └── splashscreen_image.png │ │ │ │ ├── drawable-xhdpi │ │ │ │ └── splashscreen_image.png │ │ │ │ ├── drawable-xxhdpi │ │ │ │ └── splashscreen_image.png │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── splashscreen_image.png │ │ │ │ ├── drawable │ │ │ │ ├── rn_edit_text_material.xml │ │ │ │ └── splashscreen.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── values-night │ │ │ │ └── colors.xml │ │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── release │ │ │ └── java │ │ │ └── com │ │ │ └── keys │ │ │ └── development │ │ │ └── ReactNativeFlipper.java │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.config.js ├── assets │ ├── adaptive-icon.png │ ├── favicon.png │ ├── icon.png │ └── splash.png ├── babel.config.js ├── eas.json ├── ios │ ├── .gitignore │ ├── .xcode.env │ ├── Podfile │ ├── Podfile.lock │ ├── Podfile.properties.json │ ├── devapp.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── devapp.xcscheme │ ├── devapp.xcworkspace │ │ └── contents.xcworkspacedata │ └── devapp │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── App-Icon-1024x1024@1x.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── SplashScreen.imageset │ │ │ ├── Contents.json │ │ │ └── image.png │ │ └── SplashScreenBackground.imageset │ │ │ ├── Contents.json │ │ │ └── image.png │ │ ├── Info.plist │ │ ├── SplashScreen.storyboard │ │ ├── Supporting │ │ └── Expo.plist │ │ ├── devapp-Bridging-Header.h │ │ ├── devapp.entitlements │ │ ├── main.m │ │ └── noop-file.swift ├── keys.development.json ├── keys.production.json ├── keys.staging.json ├── metro.config.js ├── package.json ├── react-native.config.js ├── src │ └── App.tsx ├── tsconfig.json ├── webpack.config.js └── yarn.lock ├── ios ├── GeneratedDotEnv.m ├── Keys.h ├── Keys.mm ├── Keys.xcodeproj │ └── project.pbxproj ├── YeetJSIUtils.h └── YeetJSIUtils.mm ├── keysAndroid.js ├── keysIOS.js ├── lefthook.yml ├── media ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── flowchart.jpg └── keys.png ├── package.json ├── plugin ├── src │ ├── android │ │ ├── addProductFlavors.ts │ │ ├── buildGradleProperties.ts │ │ ├── buildscriptDependency.ts │ │ └── index.ts │ ├── index.ts │ ├── ios │ │ ├── index.ts │ │ └── preactionScript.ts │ └── pluginConfig.ts └── tsconfig.json ├── react-native-keys.podspec ├── scripts └── bootstrap.js ├── src ├── __tests__ │ └── index.test.tsx ├── index.ts ├── spec │ └── NativeKeys.ts ├── type.ts └── util │ ├── common.js │ ├── keysFilesTemplateAndroid.js │ └── keysFilesTemplateIos.js ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | executors: 4 | default: 5 | docker: 6 | - image: circleci/node:10 7 | working_directory: ~/project 8 | 9 | commands: 10 | attach_project: 11 | steps: 12 | - attach_workspace: 13 | at: ~/project 14 | 15 | jobs: 16 | install-dependencies: 17 | executor: default 18 | steps: 19 | - checkout 20 | - attach_project 21 | - restore_cache: 22 | keys: 23 | - dependencies-{{ checksum "package.json" }} 24 | - dependencies- 25 | - restore_cache: 26 | keys: 27 | - dependencies-example-{{ checksum "example/package.json" }} 28 | - dependencies-example- 29 | - run: 30 | name: Install dependencies 31 | command: | 32 | yarn install --cwd example --frozen-lockfile 33 | yarn install --frozen-lockfile 34 | - save_cache: 35 | key: dependencies-{{ checksum "package.json" }} 36 | paths: node_modules 37 | - save_cache: 38 | key: dependencies-example-{{ checksum "example/package.json" }} 39 | paths: example/node_modules 40 | - persist_to_workspace: 41 | root: . 42 | paths: . 43 | 44 | lint: 45 | executor: default 46 | steps: 47 | - attach_project 48 | - run: 49 | name: Lint files 50 | command: | 51 | yarn lint 52 | 53 | typescript: 54 | executor: default 55 | steps: 56 | - attach_project 57 | - run: 58 | name: Typecheck files 59 | command: | 60 | yarn typescript 61 | 62 | unit-tests: 63 | executor: default 64 | steps: 65 | - attach_project 66 | - run: 67 | name: Run unit tests 68 | command: | 69 | yarn test --coverage 70 | - store_artifacts: 71 | path: coverage 72 | destination: coverage 73 | 74 | build-package: 75 | executor: default 76 | steps: 77 | - attach_project 78 | - run: 79 | name: Build package 80 | command: | 81 | yarn prepare 82 | 83 | workflows: 84 | build-and-test: 85 | jobs: 86 | - install-dependencies 87 | - lint: 88 | requires: 89 | - install-dependencies 90 | - typescript: 91 | requires: 92 | - install-dependencies 93 | - unit-tests: 94 | requires: 95 | - install-dependencies 96 | - build-package: 97 | requires: 98 | - install-dependencies 99 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: numandev1 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: http://buymeacoffee.com/numan.dev 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Current behavior 11 | 12 | ### Expected behavior 13 | 14 | ### Platform 15 | 16 | - [X] Android 17 | - [X] iOS 18 | 19 | ### React Native Version 20 | 21 | ### React Native Compressor Version 22 | 23 | ### Reproducible Steps And Demo 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Summary 4 | 5 | 6 | 7 | ## Changelog 8 | 9 | 10 | 11 | [CATEGORY] [TYPE] - Message 12 | 13 | ## Test Plan 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | # Number of days of inactivity before an issue becomes stale 3 | daysUntilStale: 30 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 7 6 | # Issues with these labels will never be considered stale 7 | exemptLabels: 8 | - enhancement 9 | # Label to use when marking an issue as stale 10 | staleLabel: Stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. 14 | Thank you for your contributions. 15 | # Comment to post when closing a stale issue. Set to `false` to disable 16 | closeComment: > 17 | Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information. 18 | only: issues 19 | -------------------------------------------------------------------------------- /.github/workflows/build-android.yml: -------------------------------------------------------------------------------- 1 | name: Build Android App 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '.github/workflows/build-android.yml' 9 | - 'android/**' 10 | - 'example/android/**' 11 | - 'yarn.lock' 12 | - 'example/yarn.lock' 13 | pull_request: 14 | paths: 15 | - '.github/workflows/build-android.yml' 16 | - 'android/**' 17 | - 'example/android/**' 18 | - 'yarn.lock' 19 | - 'example/yarn.lock' 20 | 21 | jobs: 22 | build: 23 | name: Build Android Example App 24 | runs-on: ubuntu-latest 25 | defaults: 26 | run: 27 | working-directory: example/android 28 | steps: 29 | - uses: actions/checkout@v2 30 | 31 | - name: Setup JDK 11 32 | uses: actions/setup-java@v1 33 | with: 34 | java-version: 11 35 | 36 | - name: Get yarn cache directory path 37 | id: yarn-cache-dir-path 38 | run: echo "::set-output name=dir::$(yarn cache dir)" 39 | - name: Restore node_modules from cache 40 | uses: actions/cache@v2 41 | id: yarn-cache 42 | with: 43 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 44 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 45 | restore-keys: | 46 | ${{ runner.os }}-yarn- 47 | - name: Install node_modules for example/ 48 | run: yarn install --frozen-lockfile --cwd .. 49 | 50 | - name: Restore Gradle cache 51 | uses: actions/cache@v2 52 | with: 53 | path: | 54 | ~/.gradle/caches 55 | ~/.gradle/wrapper 56 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 57 | restore-keys: | 58 | ${{ runner.os }}-gradle- 59 | - name: Run Gradle Build 60 | run: ./gradlew assembleDebug 61 | -------------------------------------------------------------------------------- /.github/workflows/build-ios.yml: -------------------------------------------------------------------------------- 1 | name: Build iOS App 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '.github/workflows/build-ios.yml' 9 | - 'ios/**' 10 | - '*.podspec' 11 | - 'example/ios/**' 12 | pull_request: 13 | paths: 14 | - '.github/workflows/build-ios.yml' 15 | - 'ios/**' 16 | - '*.podspec' 17 | - 'example/ios/**' 18 | 19 | jobs: 20 | build: 21 | name: Build iOS Example App 22 | runs-on: macOS-latest 23 | defaults: 24 | run: 25 | working-directory: example/ios 26 | steps: 27 | - uses: actions/checkout@v2 28 | 29 | - name: Get yarn cache directory path 30 | id: yarn-cache-dir-path 31 | run: echo "::set-output name=dir::$(yarn cache dir)" 32 | - name: Restore node_modules from cache 33 | uses: actions/cache@v2 34 | id: yarn-cache 35 | with: 36 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 37 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 38 | restore-keys: | 39 | ${{ runner.os }}-yarn- 40 | - name: Install node_modules for example/ 41 | run: yarn install --frozen-lockfile --cwd .. 42 | 43 | - name: Setup Ruby (bundle) 44 | uses: ruby/setup-ruby@v1 45 | with: 46 | ruby-version: 2.6 47 | bundler-cache: true 48 | working-directory: example/ios 49 | 50 | - name: Restore Pods cache 51 | uses: actions/cache@v2 52 | with: 53 | path: | 54 | example/ios/Pods 55 | ~/Library/Caches/CocoaPods 56 | ~/.cocoapods 57 | key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} 58 | restore-keys: | 59 | ${{ runner.os }}-pods- 60 | - name: Install Pods 61 | run: bundle exec pod check || bundle exec pod install 62 | - name: Build App 63 | run: "xcodebuild \ 64 | -workspace CompressorExample.xcworkspace \ 65 | -scheme CompressorExample \ 66 | -sdk iphonesimulator \ 67 | -configuration Debug \ 68 | -destination \"generic/platform=iOS Simulator\" \ 69 | build \ 70 | CODE_SIGNING_ALLOWED=NO" 71 | -------------------------------------------------------------------------------- /.github/workflows/first-issue-or-pr.yml: -------------------------------------------------------------------------------- 1 | name: First Issue Or PR 2 | on: 3 | pull_request: 4 | types: [opened, closed] 5 | issues: 6 | types: [opened] 7 | jobs: 8 | run: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: wow-actions/welcome@v1 12 | with: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | FIRST_ISSUE: | 15 | 👋 @{{ author }} 16 | Thanks for opening your issue here! **If you find this package useful hit the star🌟!** 17 | 18 | FIRST_PR: | 19 | 👋 @{{ author }} 20 | Thanks for opening this pull request! **If you find this package useful hit the star🌟!** 21 | -------------------------------------------------------------------------------- /.github/workflows/publishnpm.yml: -------------------------------------------------------------------------------- 1 | name: publish package to npm 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | Environment: 7 | description: 'Enter Anything' 8 | required: false 9 | default: '' 10 | 11 | jobs: 12 | publish: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: 12 19 | - run: yarn install 20 | - name: "Automated Version Bump" 21 | uses: "phips28/gh-action-bump-version@master" 22 | with: 23 | tag-prefix: '' 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | - uses: JS-DevTools/npm-publish@v1 27 | with: 28 | token: ${{ secrets.NPM_TOKEN }} 29 | -------------------------------------------------------------------------------- /.github/workflows/sponsor.yml: -------------------------------------------------------------------------------- 1 | name: Label sponsors 2 | on: 3 | pull_request: 4 | types: [opened] 5 | issues: 6 | types: [opened] 7 | 8 | jobs: 9 | build: 10 | name: is-sponsor-label 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: JasonEtco/is-sponsor-label-action@v1 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/stale-bot.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | jobs: 6 | stale: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | steps: 12 | - uses: actions/stale@v4 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | days-before-stale: 365 16 | stale-issue-message: 'This issue is stale because it has been open 365 days with no activity. Remove stale label or comment or this will be closed in 7 days.' 17 | stale-pr-message: 'This PR is stale because it has been open 365 days with no activity. Remove stale label or comment or this will be closed in 7 days.' 18 | close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' 19 | close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.' 20 | -------------------------------------------------------------------------------- /.github/workflows/validate-android.yml: -------------------------------------------------------------------------------- 1 | name: Validate Android 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '.github/workflows/validate-android.yml' 9 | - 'android/**' 10 | - '.editorconfig' 11 | pull_request: 12 | paths: 13 | - '.github/workflows/validate-android.yml' 14 | - 'android/**' 15 | - '.editorconfig' 16 | 17 | jobs: 18 | lint: 19 | name: Gradle Lint 20 | runs-on: ubuntu-latest 21 | defaults: 22 | run: 23 | working-directory: ./android 24 | steps: 25 | - uses: actions/checkout@v2 26 | - name: Setup JDK 1.8 27 | uses: actions/setup-java@v1 28 | with: 29 | java-version: 1.8 30 | 31 | - name: Get yarn cache directory path 32 | id: yarn-cache-dir-path 33 | run: echo "::set-output name=dir::$(yarn cache dir)" 34 | - name: Restore node_modules from cache 35 | uses: actions/cache@v2 36 | id: yarn-cache 37 | with: 38 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 39 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 40 | restore-keys: | 41 | ${{ runner.os }}-yarn- 42 | - name: Install node_modules 43 | run: yarn install --frozen-lockfile --cwd .. 44 | 45 | - name: Restore Gradle cache 46 | uses: actions/cache@v2 47 | with: 48 | path: | 49 | ~/.gradle/caches 50 | ~/.gradle/wrapper 51 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 52 | restore-keys: | 53 | ${{ runner.os }}-gradle- 54 | - name: Run Gradle Lint 55 | run: ./gradlew lint 56 | 57 | - name: Parse Gradle Lint Report 58 | uses: yutailang0119/action-android-lint@v1.0.2 59 | with: 60 | xml_path: android/build/reports/lint-results.xml 61 | -------------------------------------------------------------------------------- /.github/workflows/validate-js.yml: -------------------------------------------------------------------------------- 1 | name: Validate JS 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '.github/workflows/validate-js.yml' 9 | - 'src/**' 10 | - '*.json' 11 | - '*.js' 12 | - '*.lock' 13 | - 'example/src/**' 14 | - 'example/*.json' 15 | - 'example/*.js' 16 | - 'example/*.lock' 17 | - 'example/*.tsx' 18 | pull_request: 19 | paths: 20 | - '.github/workflows/validate-js.yml' 21 | - 'src/**' 22 | - '*.json' 23 | - '*.js' 24 | - '*.lock' 25 | - 'example/src/**' 26 | - 'example/*.json' 27 | - 'example/*.js' 28 | - 'example/*.lock' 29 | - 'example/*.tsx' 30 | 31 | jobs: 32 | compile: 33 | name: Compile JS (tsc) 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v2 37 | 38 | - name: Install reviewdog 39 | uses: reviewdog/action-setup@v1 40 | 41 | - name: Get yarn cache directory path 42 | id: yarn-cache-dir-path 43 | run: echo "::set-output name=dir::$(yarn cache dir)" 44 | - name: Restore node_modules from cache 45 | uses: actions/cache@v2 46 | id: yarn-cache 47 | with: 48 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 49 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 50 | restore-keys: | 51 | ${{ runner.os }}-yarn- 52 | - name: Install node_modules 53 | run: yarn install --frozen-lockfile 54 | - name: Install node_modules (example/) 55 | run: yarn install --frozen-lockfile --cwd example 56 | 57 | - name: Run TypeScript # Reviewdog tsc errorformat: %f:%l:%c - error TS%n: %m 58 | run: | 59 | yarn typescript | reviewdog -name="tsc" -efm="%f(%l,%c): error TS%n: %m" -reporter="github-pr-review" -filter-mode="nofilter" -fail-on-error -tee 60 | env: 61 | REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | 63 | lint: 64 | name: Lint JS (eslint, prettier) 65 | runs-on: ubuntu-latest 66 | steps: 67 | - uses: actions/checkout@v2 68 | 69 | - name: Get yarn cache directory path 70 | id: yarn-cache-dir-path 71 | run: echo "::set-output name=dir::$(yarn cache dir)" 72 | - name: Restore node_modules from cache 73 | uses: actions/cache@v2 74 | id: yarn-cache 75 | with: 76 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 77 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 78 | restore-keys: | 79 | ${{ runner.os }}-yarn- 80 | - name: Install node_modules 81 | run: yarn install --frozen-lockfile 82 | - name: Install node_modules (example/) 83 | run: yarn install --frozen-lockfile --cwd example 84 | 85 | - name: Run ESLint 86 | run: yarn lint -f @jamesacarr/github-actions 87 | 88 | - name: Run ESLint with auto-fix 89 | run: yarn lint --fix 90 | 91 | - name: Verify no files have changed after auto-fix 92 | run: git diff --exit-code HEAD 93 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | .cxx/ 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | ios/privateKey.m 33 | # Android/IJ 34 | # 35 | .idea 36 | .gradle 37 | local.properties 38 | android.iml 39 | android/.cxx 40 | *.hprof 41 | 42 | # Cocoapods 43 | # 44 | example/ios/Pods 45 | 46 | # node.js 47 | # 48 | node_modules/ 49 | npm-debug.log 50 | yarn-debug.log 51 | yarn-error.log 52 | 53 | # BUCK 54 | buck-out/ 55 | \.buckd/ 56 | android/app/libs 57 | android/keystores/debug.keystore 58 | 59 | # Expo 60 | .expo/* 61 | 62 | # generated by bob 63 | lib/ 64 | **prebuild.log 65 | example/ios/tmp.xcconfig 66 | 67 | src/type.ts 68 | cpp/crypto.cpp 69 | android/src/main/java/com/reactnativekeysjsi/PrivateKey.java 70 | -------------------------------------------------------------------------------- /.yarn/install-state.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/.yarn/install-state.gz -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Muhammad Numan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /android/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(react-native-keys) 2 | cmake_minimum_required(VERSION 3.9.0) 3 | 4 | set(PACKAGE_NAME "react-native-keys") 5 | set(CMAKE_VERBOSE_MAKEFILE ON) 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build) 8 | 9 | if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 71) 10 | # Consume shared libraries and headers from prefabs 11 | find_package(ReactAndroid REQUIRED CONFIG) 12 | 13 | include_directories( 14 | ${PACKAGE_NAME} 15 | "./androidcpp" 16 | "../cpp" 17 | ) 18 | 19 | file(GLOB LIBRN_DIR "${BUILD_DIR}/react-native-0*/jni/${ANDROID_ABI}") 20 | message(STATUS "LIBRN_DIR: ${LIBRN_DIR}") 21 | 22 | add_library( 23 | ${PACKAGE_NAME} 24 | SHARED 25 | ./androidcpp/mediator.cpp 26 | ./cpp-adapter.cpp 27 | ../cpp/crypto.cpp 28 | ../cpp/decryptor.cpp 29 | ) 30 | 31 | find_library( 32 | LOG_LIB 33 | log 34 | ) 35 | 36 | find_library( 37 | REACT_NATIVE_JNI_LIB 38 | reactnativejni 39 | PATHS ${LIBRN_DIR} 40 | NO_CMAKE_FIND_ROOT_PATH 41 | ) 42 | 43 | set_target_properties( 44 | ${PACKAGE_NAME} PROPERTIES 45 | CXX_STANDARD 17 46 | CXX_EXTENSIONS OFF 47 | POSITION_INDEPENDENT_CODE ON 48 | ) 49 | 50 | find_package(openssl REQUIRED CONFIG) 51 | 52 | target_link_libraries( 53 | ${PACKAGE_NAME} 54 | ${LOG_LIB} 55 | ReactAndroid::jsi 56 | android 57 | openssl::crypto 58 | ) 59 | if(${REACT_NATIVE_MINOR_VERSION} GREATER_EQUAL 76) 60 | target_link_libraries( 61 | ${PACKAGE_NAME} 62 | ReactAndroid::reactnative 63 | ) 64 | else() 65 | target_link_libraries( 66 | ${PACKAGE_NAME} 67 | ReactAndroid::reactnativejni 68 | ReactAndroid::react_nativemodule_core 69 | ) 70 | endif() 71 | else() 72 | add_library( 73 | ${PACKAGE_NAME} 74 | SHARED 75 | ../../react-native/ReactCommon/jsi/jsi/jsi.cpp 76 | ./androidcpp/mediator.cpp 77 | ./cpp-adapter.cpp 78 | ../cpp/crypto.cpp 79 | ../cpp/decryptor.cpp 80 | ) 81 | 82 | include_directories( 83 | ../../react-native/React 84 | ../../react-native/React/Base 85 | ../../react-native/ReactCommon/jsi 86 | ./cpp 87 | ../cpp 88 | ) 89 | 90 | set_target_properties( 91 | ${PACKAGE_NAME} PROPERTIES 92 | CXX_STANDARD 17 93 | CXX_EXTENSIONS OFF 94 | POSITION_INDEPENDENT_CODE ON 95 | ) 96 | 97 | find_package(openssl REQUIRED CONFIG) 98 | 99 | target_link_libraries( 100 | ${PACKAGE_NAME} 101 | android 102 | openssl::crypto 103 | ) 104 | endif() 105 | -------------------------------------------------------------------------------- /android/androidcpp/mediator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "crypto.h" 5 | 6 | std::string jstring2string(JNIEnv *env, jstring jStr) 7 | { 8 | if (!jStr) 9 | return ""; 10 | 11 | const jclass stringClass = env->GetObjectClass(jStr); 12 | const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B"); 13 | const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, 14 | env->NewStringUTF("UTF-8")); 15 | 16 | size_t length = (size_t) env->GetArrayLength(stringJbytes); 17 | jbyte *pBytes = env->GetByteArrayElements(stringJbytes, NULL); 18 | 19 | std::string ret = std::string((char *) pBytes, length); 20 | env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT); 21 | 22 | env->DeleteLocalRef(stringJbytes); 23 | env->DeleteLocalRef(stringClass); 24 | return ret; 25 | } 26 | 27 | extern "C" JNIEXPORT jstring JNICALL 28 | Java_com_reactnativekeysjsi_KeysModule_getJniJsonStringifyData(JNIEnv * env, jobject thiz,jstring key) { 29 | auto *crypto = new Crypto(); 30 | std::string _key{jstring2string(env,key)}; 31 | return env->NewStringUTF(crypto->getJniJsonStringifyData(_key).c_str()); 32 | } 33 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | Keys_kotlinVersion=1.7.0 2 | Keys_minSdkVersion=21 3 | Keys_targetSdkVersion=31 4 | Keys_compileSdkVersion=31 5 | Keys_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifestDeprecated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnativekeysjsi/KeysModule.java: -------------------------------------------------------------------------------- 1 | package com.reactnativekeysjsi; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.util.Log; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 11 | import com.facebook.react.bridge.ReactMethod; 12 | import com.facebook.react.bridge.JavaScriptContextHolder; 13 | 14 | import org.json.JSONObject; 15 | import java.lang.reflect.Field; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | public class KeysModule extends KeysSpec { 20 | public static final String NAME = "Keys"; 21 | public static ReactApplicationContext reactContext; 22 | 23 | private native void nativeInstall(long jsiPtr); 24 | 25 | public KeysModule(ReactApplicationContext reactContext) { 26 | super(reactContext); 27 | this.reactContext = reactContext; 28 | } 29 | 30 | @Override 31 | @NonNull 32 | public String getName() { 33 | return NAME; 34 | } 35 | 36 | @ReactMethod(isBlockingSynchronousMethod = true) 37 | public boolean install() { 38 | try { 39 | JavaScriptContextHolder jsContext = this.reactContext.getJavaScriptContextHolder(); 40 | this.nativeInstall(jsContext.get()); 41 | return true; 42 | } catch (Exception exception) { 43 | return false; 44 | } 45 | } 46 | 47 | static { 48 | System.loadLibrary("react-native-keys"); 49 | } 50 | 51 | public static native String getJniJsonStringifyData(String key); 52 | 53 | 54 | public static String getSecureFor(String key) { 55 | JSONObject jniData = null; 56 | try { 57 | if (jniData == null) { 58 | String privateKey = PrivateKey.privatekey; 59 | String jsonString = getJniJsonStringifyData(privateKey); 60 | jniData = new JSONObject(jsonString); 61 | } 62 | if (jniData.has(key)) { 63 | return jniData.getString(key); 64 | } 65 | } catch (Exception ignore) { 66 | return ""; 67 | } 68 | return ""; 69 | } 70 | 71 | public Map getPublicKeys() { 72 | final Map constants = new HashMap<>(); 73 | try { 74 | int resId = this.reactContext.getResources().getIdentifier("build_config_package", "string", this.reactContext.getPackageName()); 75 | 76 | String className; 77 | try { 78 | className = this.reactContext.getString(resId); 79 | } catch (Resources.NotFoundException e) { 80 | className = this.reactContext.getPackageName(); 81 | } 82 | Class clazz = Class.forName(className + ".BuildConfig"); 83 | 84 | Field[] fields = clazz.getDeclaredFields(); 85 | for (Field f : fields) { 86 | try { 87 | constants.put(f.getName(), f.get(null)); 88 | } catch (IllegalAccessException e) { 89 | Log.d("ReactNative", "ReactConfig: Could not access BuildConfig field " + f.getName()); 90 | } 91 | } 92 | } catch (ClassNotFoundException e) { 93 | Log.d("ReactNative", "ReactConfig: Could not find BuildConfig class"); 94 | } 95 | 96 | return constants; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnativekeysjsi/KeysPackage.java: -------------------------------------------------------------------------------- 1 | package com.reactnativekeysjsi; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.module.model.ReactModuleInfo; 8 | import com.facebook.react.module.model.ReactModuleInfoProvider; 9 | import com.facebook.react.TurboReactPackage; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class KeysPackage extends TurboReactPackage { 15 | 16 | @Nullable 17 | @Override 18 | public NativeModule getModule(String name, ReactApplicationContext reactContext) { 19 | if (name.equals(KeysModule.NAME)) { 20 | return new KeysModule(reactContext); 21 | } else { 22 | return null; 23 | } 24 | } 25 | 26 | @Override 27 | public ReactModuleInfoProvider getReactModuleInfoProvider() { 28 | return () -> { 29 | final Map moduleInfos = new HashMap<>(); 30 | boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 31 | moduleInfos.put( 32 | KeysModule.NAME, 33 | new ReactModuleInfo( 34 | KeysModule.NAME, 35 | KeysModule.NAME, 36 | false, // canOverrideExistingModule 37 | false, // needsEagerInit 38 | true, // hasConstants 39 | false, // isCxxModule 40 | isTurboModule // isTurboModule 41 | )); 42 | return moduleInfos; 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnativekeysjsi/PrivateKey.java: -------------------------------------------------------------------------------- 1 | 2 | // this is autogenerated, dont change within it 3 | package com.reactnativekeysjsi; 4 | 5 | public class PrivateKey { 6 | public static String privatekey="k0bymYdpGsZVFHIEEZVtzWgvGs0R6xxSgFN7wxkm/50HMLQZFQt55CR4VItVw6nrLfXATPXRxSiLHSDXvsvUupzfYPAodZsxx9VxlWBZ7g=="; 7 | } -------------------------------------------------------------------------------- /android/src/newarch/KeysSpec.java: -------------------------------------------------------------------------------- 1 | package com.reactnativekeysjsi; 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext; 4 | 5 | abstract class KeysSpec extends NativeKeysSpec { 6 | KeysSpec(ReactApplicationContext context) { 7 | super(context); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /android/src/oldarch/KeysSpec.java: -------------------------------------------------------------------------------- 1 | package com.reactnativekeysjsi; 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext; 4 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 5 | import com.facebook.react.bridge.Promise; 6 | 7 | abstract class KeysSpec extends ReactContextBaseJavaModule { 8 | KeysSpec(ReactApplicationContext context) { 9 | super(context); 10 | } 11 | public abstract boolean install(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./plugin/build'); 2 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /cpp/crypto.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "crypto.h" 3 | #include 4 | #include "decryptor.h" 5 | 6 | using namespace std; 7 | 8 | Crypto::Crypto() { 9 | 10 | } 11 | 12 | string Crypto::getJniJsonStringifyData(string key) { 13 | std::string base64Secret1 = "U2FsdGVkX19lgRN4srwXt2D2LYi+baTRYsKl2mygm7ASNIWFynY+bxsDrbKAr2MZnI0flTXS"; 14 | std::string base64Secret2 = "DPWi+ilmqhX7RviqMInOjQ/dRUApNhJW3/Sqk0bymYdpGsZVFHIEEZVtzWgvGs0R6xxSgFN7"; 15 | std::string base64Secret3 = "wxkm/50HMLQZFQt55CR4VItVw6nrLfXATPXRxSiLHSDXvsvUupzfYPAodZsxx9VxlWBZ7g=="; 16 | std::string base64Secret = base64Secret1 + base64Secret2 + base64Secret3; 17 | std::string password = "u4IxXxapI6zg"; 18 | bool binary = false; 19 | std::string plaintext = decryptor::dec(base64Secret, password,binary); 20 | 21 | string hash; 22 | string halfString=base64Secret.substr(base64Secret.length()/2); 23 | if(key==halfString) 24 | { 25 | return plaintext; 26 | } 27 | else 28 | { 29 | return ""; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cpp/crypto.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef CRYPTO_H 4 | #define CRYPTO_H 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class Crypto 11 | { 12 | public: 13 | Crypto(); 14 | string getJniJsonStringifyData(string key); 15 | }; 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /cpp/decryptor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Numan on 31/05/2023. 3 | // 4 | 5 | #include "decryptor.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | std::vector decryptor::base64_decode(const std::string& input) { 19 | BIO* b64 = BIO_new(BIO_f_base64()); 20 | BIO* bmem = BIO_new_mem_buf(input.c_str(), input.length()); 21 | bmem = BIO_push(b64, bmem); 22 | 23 | BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL); 24 | std::vector output(input.length()); 25 | 26 | int decoded_length = BIO_read(bmem, output.data(), output.size()); 27 | BIO_free_all(bmem); 28 | 29 | if (decoded_length < 0) { 30 | throw std::runtime_error("Base64 decoding error."); 31 | } 32 | 33 | output.resize(decoded_length); 34 | return output; 35 | } 36 | 37 | struct OpenSSLKeyResult { 38 | std::vector key; 39 | std::vector iv; 40 | }; 41 | 42 | decryptor::OpenSSLKeyResult decryptor::openSSLKey(const std::vector& password, const std::vector& salt) { 43 | OpenSSLKeyResult result; 44 | 45 | const EVP_CIPHER* cipher = EVP_get_cipherbyname("aes-256-cbc"); 46 | std::vector key(EVP_CIPHER_key_length(cipher)); 47 | std::vector iv(EVP_CIPHER_iv_length(cipher)); 48 | 49 | EVP_BytesToKey( 50 | cipher, 51 | EVP_md5(), 52 | salt.data(), 53 | password.data(), 54 | password.size(), 55 | 1, 56 | key.data(), 57 | iv.data() 58 | ); 59 | 60 | result.key = key; 61 | result.iv = iv; 62 | 63 | return result; 64 | } 65 | 66 | std::vector decryptor::rawDecrypt(const std::vector& input, const std::vector& key, const std::vector& iv) { 67 | std::vector output(input.size() + EVP_MAX_BLOCK_LENGTH); 68 | int output_length = 0; 69 | 70 | EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); 71 | EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key.data(), iv.data()); 72 | 73 | EVP_DecryptUpdate(ctx, output.data(), &output_length, input.data(), input.size()); 74 | 75 | int final_length = 0; 76 | EVP_DecryptFinal_ex(ctx, output.data() + output_length, &final_length); 77 | 78 | EVP_CIPHER_CTX_free(ctx); 79 | 80 | output.resize(output_length + final_length); 81 | return output; 82 | } 83 | 84 | std::string decryptor::dec(const std::string& input, const std::string& password, bool binary) { 85 | std::vector cryptArr = base64_decode(input); 86 | std::vector salt(cryptArr.begin() + 8, cryptArr.begin() + 16); 87 | 88 | OpenSSLKeyResult pbe = openSSLKey(std::vector(password.begin(), password.end()), salt); 89 | std::vector& key = pbe.key; 90 | std::vector& iv = pbe.iv; 91 | 92 | cryptArr = std::vector(cryptArr.begin() + 16, cryptArr.end()); 93 | std::vector decrypted = rawDecrypt(cryptArr, key, iv); 94 | 95 | std::string result(decrypted.begin(), decrypted.end()); 96 | return result; 97 | } 98 | -------------------------------------------------------------------------------- /cpp/decryptor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Numan on 31/05/2023. 3 | // 4 | 5 | #ifndef EXAMPLE_DECRYPTOR_H 6 | #define EXAMPLE_DECRYPTOR_H 7 | #include 8 | #include 9 | 10 | class decryptor { 11 | public: 12 | static std::string dec(const std::string& input, const std::string& password, bool binary); 13 | static std::vector base64_decode(const std::string& input); 14 | struct OpenSSLKeyResult { 15 | std::vector key; 16 | std::vector iv; 17 | }; 18 | static OpenSSLKeyResult openSSLKey(const std::vector& password, const std::vector& salt); 19 | static std::vector rawDecrypt(const std::vector& input, const std::vector& key, const std::vector& iv); 20 | private: 21 | 22 | 23 | }; 24 | 25 | 26 | #endif //EXAMPLE_DECRYPTOR_H 27 | -------------------------------------------------------------------------------- /docs/react-native-config-migration-guide.md: -------------------------------------------------------------------------------- 1 | # Migration from react-native-config 2 | 3 | | react-native-config | react-native-keys | 4 | | ---- | ----- | 5 | | .env.development

BASE_URL=https://www.example.com
APP_NAME=Example
GOOGLE_API=ABCDEF
BRANCH_API=ABCDEF
PACKAGE_ID=com.example.rnkeys.dev
| keys.development.json

{
  "secure": {
    "GOOGLE_API": "ABCD",
    "BRANCH_API": "ABCDEF"
  },
  "public": {
   "APP_NAME": "dev RNKEYS",
    "PACKAGE_ID": "com.example.rnkeys.dev"
  }
}
| 6 | | Android: apply a plugin to your app, from android/app/build.gradle:

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" | Android: apply a plugin to your app, from android/app/build.gradle:

apply from: project(':react-native-keys').projectDir.getPath() + "/RNKeys.gradle" | 7 | |Android (build.gradle):
project.ext.envConfigFiles = [
debug: ".env.development",
release: ".env.production",
anothercustombuild: ".env",
]
|Android (build.gradle):
project.ext.keyFiles = [
debug: "keys.development.json",
release: "keys.staging.json",
release: "keys.json",
]
| 8 | |Android (.Java File):
BuildConfig.GOOGLE_MAPS_API_KEY
BuildConfig.PACKAGE_ID
|Android (.Java File):
import static com.reactnativekeysjsi.KeysModule.getSecureFor;

getSecureFor("GOOGLE_MAPS_API_KEY")

BuildConfig.PACKAGE_ID
| 9 | | Android: You can also read them from your Gradle configuration:
defaultConfig {
applicationId project.env.get("APP_ID")
}
| Android: You can also read them from your Gradle configuration:
defaultConfig {
applicationId project.keys.get("APP_ID")
}
| 10 | |
import Config from "react-native-config";

Config.GOOGLE_MAPS_API_KEY;
Config.PACKAGE_ID;
|
import Keys from 'react-native-keys';

Keys.secureFor('GOOGLE_MAPS_API_KEY');
Keys.PACKAGE_ID;
| 11 | | IOS
#import "RNCConfig.h"

NSString *googleMapApiKey = [RNCConfig envFor:@"GOOGLE_MAPS_API_KEY"];
NSString *appName = [RNCConfig envFor:@"APP_NAME"];
| IOS
#import "Keys.h"

NSString *googleMapApiKey = [Keys secureFor:@"GOOGLE_MAPS_API_KEY"];
NSString *appName = [Keys publicFor:@"APP_NAME"];
| 12 | |IOS

Go to Edit scheme... -> Build -> Pre-actions,
click + and select New Run Script Action

"`$`{SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb"
"`$`{SRCROOT}/.." "`$`{SRCROOT}/tmp.xcconfig"
|IOS

Go to Edit scheme... -> Build -> Pre-actions,
click + and select New Run Script Action

export KEYSFILE=keys.development.json
"`$`{SRCROOT}/../node_modules/react-native-keys/keysIOS.js"
| 13 | -------------------------------------------------------------------------------- /docs/workflow.md: -------------------------------------------------------------------------------- 1 | # If you are Hacker or Attacker then this challenge is for you 2 | 3 | If you are a good attacker or hacker then here is APK: https://drive.google.com/file/d/1tx-NoU5LJzSw78x27wFDMgzw5c74qLkR/view?usp=sharing, I have stored the key name: `API_KEY_FOR_DECOMPILE`, can you try to decompile the value of this key 4 | 5 | # How we are protecting ENVs on the app side? 6 | 7 |
8 | 9 |
10 | 11 | We don't keep original secure keys anywhere like in Java, Objective-C, or javascript, we convert secure keys into multiple hashes using a dynamic [Ciper](https://en.wikipedia.org/wiki/Cipher) and keep these multiple hashes and [Ciper](https://en.wikipedia.org/wiki/Cipher) into C++ so during build it goes into assembly language not a Smali file, in assembly language it is very hard to extract multiple hashes, combine it and [Ciper](https://en.wikipedia.org/wiki/Cipher) and decrypt hashing using [Ciper](https://en.wikipedia.org/wiki/Cipher) 12 | 13 | we are using dynamic [Ciper](https://en.wikipedia.org/wiki/Cipher) for encoding secure keys, which means we convert secure keys into hash by using [Ciper](https://en.wikipedia.org/wiki/Cipher) (you can say dynamic password) after getting hash we are splitting this hash into 3 parts (3 substrings or 3 chunks of hash) and save these 3 chunks of string in C++ different variables, for decoding we have to integrate 3 Chunks of hash strings generated from Ciper + have to open the lock using [Ciper](https://en.wikipedia.org/wiki/Cipher) for decoding original secure keys, we also save half of the hash on Java and Objective-C, whenever user call `secureFor` method, On java or Objective-C send this half key to C++ method which combine 3 chunks of hash string, divide into half of the hash and then match this the half key with being sent from java or Objective-C side if it matches then we decrypt the key from the hash and return the key from assembly(compiled c++) 14 | **Note: Secure key comes into existence on runtime** 15 | 16 | > It’s important to understand that no system is completely secure from attacks, even every wifi device or laptop password is also hackable, I made this for making a good security measurement for preventing 3rd party API key abuse, Good security measure is better than nothing to do 17 | > Before using this package our 3rd party API key had a 99% hackable probability but after using this package hack probability will be 0.5% 18 | 19 | as far as I know, we can abuse all types of 3rd parties unless these 3rd party uses 20 | 21 | - DeviceCheck or App Attest for IOS 22 | - Play Integrity or SafetyNet for Android 23 | - or in one package firebase-appcheck supported both platform 24 | -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 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 | gem 'cocoapods', '~> 1.12' 7 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | ## Get started 2 | 3 | To try the playground out for yourself, run the following commands: 4 | 5 | ```sh 6 | git clone 7 | cd example 8 | yarn 9 | ``` 10 | 11 | ### iOS 12 | 13 | 1. Open the example/ios/KeysExample.xcworkspace file with Xcode 14 | 2. Change signing configuration to your developer account 15 | 3. Select your device in the devices drop-down 16 | 4. Hit run 17 | 18 | ### Android 19 | 20 | 1. Open the example/android/ folder with Android Studio 21 | 2. Select your device in the devices drop-down 22 | 3. Hit run 23 | 24 | ### Enable New Arch 25 | 26 | #### Android 27 | 28 | You will only need to update your android/gradle.properties file as follows: 29 | 30 | ```diff 31 | # Use this property to enable support to the new architecture. 32 | # This will allow you to use TurboModules and the Fabric render in 33 | # your application. You should enable this flag either if you want 34 | # to write custom TurboModules/Fabric components OR use libraries that 35 | # are providing them. 36 | - newArchEnabled=false 37 | + newArchEnabled=true 38 | ``` 39 | 40 | #### IOS 41 | 42 | You will only need to reinstall your pods by running pod install with the right flag: 43 | 44 | ```sh 45 | # Run pod install with the flag: 46 | RCT_NEW_ARCH_ENABLED=1 bundle exec pod install 47 | ``` 48 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/example/android/app/debug.keystore -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/android/app/src/debug/java/com/keysexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.keysexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 21 | import com.facebook.react.ReactInstanceEventListener; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.bridge.ReactContext; 24 | import com.facebook.react.modules.network.NetworkingModule; 25 | import okhttp3.OkHttpClient; 26 | 27 | /** 28 | * Class responsible of loading Flipper inside your React Native application. This is the debug 29 | * flavor of it. Here you can add your own plugins and customize the Flipper setup. 30 | */ 31 | public class ReactNativeFlipper { 32 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 33 | if (FlipperUtils.shouldEnableFlipper(context)) { 34 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 35 | 36 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 37 | client.addPlugin(new DatabasesFlipperPlugin(context)); 38 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 39 | client.addPlugin(CrashReporterPlugin.getInstance()); 40 | 41 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 42 | NetworkingModule.setCustomClientBuilder( 43 | new NetworkingModule.CustomClientBuilder() { 44 | @Override 45 | public void apply(OkHttpClient.Builder builder) { 46 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 47 | } 48 | }); 49 | client.addPlugin(networkFlipperPlugin); 50 | client.start(); 51 | 52 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 53 | // Hence we run if after all native modules have been initialized 54 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 55 | if (reactContext == null) { 56 | reactInstanceManager.addReactInstanceEventListener( 57 | new ReactInstanceEventListener() { 58 | @Override 59 | public void onReactContextInitialized(ReactContext reactContext) { 60 | reactInstanceManager.removeReactInstanceEventListener(this); 61 | reactContext.runOnNativeModulesQueueThread( 62 | new Runnable() { 63 | @Override 64 | public void run() { 65 | client.addPlugin(new FrescoFlipperPlugin()); 66 | } 67 | }); 68 | } 69 | }); 70 | } else { 71 | client.addPlugin(new FrescoFlipperPlugin()); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/keysexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.keysexample; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactActivityDelegate; 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate; 7 | 8 | public class MainActivity extends 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 15 | protected String getMainComponentName() { 16 | return "KeysExample"; 17 | } 18 | 19 | /** 20 | * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link 21 | * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React 22 | * (aka React 18) with two boolean flags. 23 | */ 24 | @Override 25 | protected ReactActivityDelegate createReactActivityDelegate() { 26 | return new DefaultReactActivityDelegate( 27 | this, 28 | getMainComponentName(), 29 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 30 | DefaultNewArchitectureEntryPoint.getFabricEnabled()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/keysexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.keysexample; 2 | 3 | import static com.reactnativekeysjsi.KeysModule.getSecureFor; 4 | import android.util.Log; 5 | 6 | import android.app.Application; 7 | import com.facebook.react.PackageList; 8 | import com.facebook.react.ReactApplication; 9 | import com.facebook.react.ReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 12 | import com.facebook.react.defaults.DefaultReactNativeHost; 13 | import com.facebook.soloader.SoLoader; 14 | import java.util.List; 15 | 16 | public class MainApplication extends Application implements ReactApplication { 17 | 18 | private final ReactNativeHost mReactNativeHost = 19 | new DefaultReactNativeHost(this) { 20 | @Override 21 | public boolean getUseDeveloperSupport() { 22 | return BuildConfig.DEBUG; 23 | } 24 | 25 | @Override 26 | protected List getPackages() { 27 | @SuppressWarnings("UnnecessaryLocalVariable") 28 | List packages = new PackageList(this).getPackages(); 29 | // Packages that cannot be autolinked yet can be added manually here, for example: 30 | // packages.add(new MyReactNativePackage()); 31 | return packages; 32 | } 33 | 34 | @Override 35 | protected String getJSMainModuleName() { 36 | return "index"; 37 | } 38 | 39 | @Override 40 | protected boolean isNewArchEnabled() { 41 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 42 | } 43 | 44 | @Override 45 | protected Boolean isHermesEnabled() { 46 | return BuildConfig.IS_HERMES_ENABLED; 47 | } 48 | }; 49 | 50 | @Override 51 | public ReactNativeHost getReactNativeHost() { 52 | return mReactNativeHost; 53 | } 54 | 55 | @Override 56 | public void onCreate() { 57 | super.onCreate(); 58 | SoLoader.init(this, /* native exopackage */ false); 59 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 60 | // If you opted-in for the New Architecture, we load the native entry point for this app. 61 | DefaultNewArchitectureEntryPoint.load(); 62 | } 63 | String secureValue = getSecureFor("secure3"); 64 | String publicValue = BuildConfig.APP_NAME; 65 | Log.d("secure(JNI)", "this value is from secure: " + secureValue); 66 | Log.d("secure(JNI)", "this value is from public: " + publicValue); 67 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | KeysExample 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/app/src/release/java/com/keysexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.keysexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.react.ReactInstanceManager; 11 | 12 | /** 13 | * Class responsible of loading Flipper inside your React Native application. This is the release 14 | * flavor of it so it's empty as we don't want to load Flipper. 15 | */ 16 | public class ReactNativeFlipper { 17 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 18 | // Do nothing as we don't want to initialize Flipper on Release. 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "33.0.0" 6 | minSdkVersion = 21 7 | compileSdkVersion = 33 8 | targetSdkVersion = 33 9 | 10 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. 11 | ndkVersion = "23.1.7779620" 12 | } 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | dependencies { 18 | classpath("com.android.tools.build:gradle") 19 | classpath("com.facebook.react:react-native-gradle-plugin") 20 | } 21 | } 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 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.182.0 29 | 30 | # Use this property to specify which architecture you want to build. 31 | # You can also override it from the CLI using 32 | # ./gradlew -PreactNativeArchitectures=x86_64 33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 34 | 35 | # Use this property to enable support to the new architecture. 36 | # This will allow you to use TurboModules and the Fabric render in 37 | # your application. You should enable this flag either if you want 38 | # to write custom TurboModules/Fabric components OR use libraries that 39 | # are providing them. 40 | newArchEnabled=false 41 | 42 | # Use this property to enable or disable the Hermes JS engine. 43 | # If set to false, you will be using JSC instead. 44 | hermesEnabled=true 45 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/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.0.1-all.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'KeysExample' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/@react-native/gradle-plugin') 5 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "KeysExample", 3 | "displayName": "KeysExample" 4 | } 5 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:metro-react-native-babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /example/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /example/ios/Config.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Config.xcconfig 3 | // KeysExample 4 | 5 | // Configuration settings file format documentation can be found at: 6 | // https://help.apple.com/xcode/#/dev745c5c974 7 | #include? "tmp.xcconfig" -------------------------------------------------------------------------------- /example/ios/KeysExample.xcodeproj/xcshareddata/xcschemes/KeysExample-Dev.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 11 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 51 | 57 | 58 | 59 | 60 | 61 | 71 | 73 | 79 | 80 | 81 | 82 | 88 | 90 | 96 | 97 | 98 | 99 | 101 | 102 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /example/ios/KeysExample.xcodeproj/xcshareddata/xcschemes/KeysExample-Production.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 11 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 51 | 57 | 58 | 59 | 60 | 61 | 71 | 73 | 79 | 80 | 81 | 82 | 88 | 90 | 96 | 97 | 98 | 99 | 101 | 102 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /example/ios/KeysExample.xcodeproj/xcshareddata/xcschemes/KeysExample-Staging.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 11 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 51 | 57 | 58 | 59 | 60 | 61 | 71 | 73 | 79 | 80 | 81 | 82 | 88 | 90 | 96 | 97 | 98 | 99 | 101 | 102 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /example/ios/KeysExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/KeysExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/KeysExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/KeysExample/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "Keys.h" 2 | #import "AppDelegate.h" 3 | 4 | 5 | #import 6 | 7 | @implementation AppDelegate 8 | 9 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 10 | { 11 | self.moduleName = @"KeysExample"; 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 | NSString *publicValue = [Keys publicFor:@"public2"]; 16 | NSLog(@"publicValue2: %@", publicValue); 17 | 18 | NSString *secureValue = [Keys secureFor:@"secure1"]; 19 | NSLog(@"secureValue1: %@",secureValue); 20 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 21 | } 22 | 23 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 24 | { 25 | #if DEBUG 26 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 27 | #else 28 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 29 | #endif 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /example/ios/KeysExample/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/KeysExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/KeysExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | KeysExample 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 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /example/ios/KeysExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/KeysExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/ios/KeysExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/KeysExampleTests/KeysExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface KeysExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation KeysExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. 12 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded 13 | # 14 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` 15 | # ```js 16 | # module.exports = { 17 | # dependencies: { 18 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), 19 | # ``` 20 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled 21 | 22 | linkage = ENV['USE_FRAMEWORKS'] 23 | if linkage != nil 24 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 25 | use_frameworks! :linkage => linkage.to_sym 26 | end 27 | 28 | target 'KeysExample' do 29 | config = use_native_modules! 30 | 31 | # Flags change depending on the env values. 32 | flags = get_default_flags() 33 | 34 | use_react_native!( 35 | :path => config[:reactNativePath], 36 | # Hermes is now enabled by default. Disable by setting this flag to false. 37 | :hermes_enabled => flags[:hermes_enabled], 38 | :fabric_enabled => flags[:fabric_enabled], 39 | # Enables Flipper. 40 | # 41 | # Note that if you have use_frameworks! enabled, Flipper will not work and 42 | # you should disable the next line. 43 | :flipper_configuration => flipper_config, 44 | # An absolute path to your application root. 45 | :app_path => "#{Pod::Config.instance.installation_root}/.." 46 | ) 47 | pod 'react-native-keys', :path => '../..' 48 | target 'KeysExampleTests' do 49 | inherit! :complete 50 | # Pods for testing 51 | end 52 | 53 | post_install do |installer| 54 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 55 | react_native_post_install( 56 | installer, 57 | config[:reactNativePath], 58 | :mac_catalyst_enabled => false 59 | ) 60 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /example/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /example/keys.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "secure": { 3 | "secure1": "dev secure1 value", 4 | "secure2": "dev secure2 value", 5 | "secure3": "dev secure3 value", 6 | "GOOGLE_API": "ABCD", 7 | "BRANCH_API": "ABCDEF" 8 | }, 9 | "public": { 10 | "APP_NAME": "dev RNKEYS", 11 | "BUNDLE_ID": "com.example.rnkeys.dev", 12 | "ANDROID_CODE": "50", 13 | "PACKAGE_ID": "com.example.rnkeys.dev", 14 | "public1": "dev numan", 15 | "public2": "dev usman" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/keys.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "secure": { 3 | "secure1": "prod secure1 value", 4 | "secure2": "prod secure2 value", 5 | "secure3": "prod secure3 value", 6 | "GOOGLE_API": "ABCD", 7 | "BRANCH_API": "ABCDEF" 8 | }, 9 | "public": { 10 | "APP_NAME": "prod RNKEYS", 11 | "BUNDLE_ID": "com.example.rnkeys.prod", 12 | "ANDROID_CODE": "50", 13 | "PACKAGE_ID": "com.example.rnkeys.prod", 14 | "public1": "prod numan", 15 | "public2": "prod usman" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/keys.staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "secure": { 3 | "secure1": "staging secure1 value", 4 | "secure2": "staging secure2 value", 5 | "secure3": "staging secure3 value", 6 | "GOOGLE_API": "ABCD", 7 | "BRANCH_API": "ABCDEF" 8 | }, 9 | "public": { 10 | "APP_NAME": "staging RNKEYS", 11 | "BUNDLE_ID": "com.example.rnkeys.staging", 12 | "ANDROID_CODE": "50", 13 | "PACKAGE_ID": "com.example.rnkeys.staging", 14 | "public1": "staging numan", 15 | "public2": "staging usman" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 2 | const path = require('path'); 3 | const escape = require('escape-string-regexp'); 4 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 5 | const pak = require('../package.json'); 6 | 7 | const root = path.resolve(__dirname, '..'); 8 | const modules = Object.keys({ ...pak.peerDependencies }); 9 | 10 | /** 11 | * Metro configuration 12 | * https://facebook.github.io/metro/docs/configuration 13 | * 14 | * @type {import('metro-config').MetroConfig} 15 | */ 16 | const config = { 17 | watchFolders: [root], 18 | 19 | // We need to make sure that only one version is loaded for peerDependencies 20 | // So we block them at the root, and alias them to the versions in example's node_modules 21 | resolver: { 22 | blacklistRE: exclusionList( 23 | modules.map( 24 | (m) => 25 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 26 | ) 27 | ), 28 | 29 | extraNodeModules: modules.reduce((acc, name) => { 30 | acc[name] = path.join(__dirname, 'node_modules', name); 31 | return acc; 32 | }, {}), 33 | }, 34 | 35 | transformer: { 36 | getTransformOptions: async () => ({ 37 | transform: { 38 | experimentalImportSupport: false, 39 | inlineRequires: true, 40 | }, 41 | }), 42 | }, 43 | }; 44 | 45 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 46 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "KeysExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "pods": "pod-install --quiet", 10 | "pods-newarch": "cd ios && RCT_NEW_ARCH_ENABLED=1 pod install", 11 | "android-build-assets": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/", 12 | "android-dev": "react-native run-android --variant=developmentDebug --appIdSuffix dev", 13 | "android-dev-kyc": "react-native run-android --variant=developmentDebug", 14 | "ios-dev": "react-native run-ios --scheme=KeysExample-Dev --simulator='iPhone 14'", 15 | "android-staging": "react-native run-android --variant=stagingDebug --appIdSuffix staging", 16 | "android-staging-prod": "react-native run-android --variant=stagingRelease --appIdSuffix staging", 17 | "ios-staging": "react-native run-ios --scheme=KeysExample-Staging --simulator='iPhone 14'", 18 | "android-prod": "react-native run-android --variant=productionRelease", 19 | "ios-prod": "react-native run-ios --scheme=KeysExample-Production", 20 | "android-dev-prod": "react-native run-android --variant=developmentRelease" 21 | }, 22 | "dependencies": { 23 | "react": "18.2.0", 24 | "react-native": "0.72.3" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.20.0", 28 | "@babel/preset-env": "^7.20.0", 29 | "@babel/runtime": "^7.20.0", 30 | "@react-native/eslint-config": "^0.72.2", 31 | "@react-native/metro-config": "^0.72.9", 32 | "metro-react-native-babel-preset": "0.76.7", 33 | "babel-plugin-module-resolver": "^5.0.0" 34 | }, 35 | "engines": { 36 | "node": ">=16" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { StyleSheet, Text, View } from 'react-native'; 3 | import RNKeys from 'react-native-keys'; 4 | 5 | export default function App() { 6 | const [jniValue] = useState(RNKeys.secureFor('secure3')); 7 | const [publicValue] = useState(RNKeys.APP_NAME); 8 | 9 | return ( 10 | 11 | KEY FROM SECURE (JNI): {jniValue} 12 | KEY FROM PUBLIC: {publicValue} 13 | 14 | ); 15 | } 16 | 17 | const styles = StyleSheet.create({ 18 | container: { 19 | flex: 1, 20 | alignItems: 'center', 21 | justifyContent: 'center', 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /exampleExpo/App.js: -------------------------------------------------------------------------------- 1 | export { default } from './src/App'; 2 | -------------------------------------------------------------------------------- /exampleExpo/android/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Android/IntelliJ 6 | # 7 | build/ 8 | .idea 9 | .gradle 10 | local.properties 11 | *.iml 12 | *.hprof 13 | 14 | # Bundle artifacts 15 | *.jsbundle 16 | -------------------------------------------------------------------------------- /exampleExpo/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/debug.keystore -------------------------------------------------------------------------------- /exampleExpo/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 | # react-native-reanimated 11 | -keep class com.swmansion.reanimated.** { *; } 12 | -keep class com.facebook.react.turbomodule.** { *; } 13 | 14 | # Add any project specific keep options here: 15 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/debug/java/com/keys/development/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.keys.development; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 21 | import com.facebook.react.ReactInstanceEventListener; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.bridge.ReactContext; 24 | import com.facebook.react.modules.network.NetworkingModule; 25 | import okhttp3.OkHttpClient; 26 | 27 | /** 28 | * Class responsible of loading Flipper inside your React Native application. This is the debug 29 | * flavor of it. Here you can add your own plugins and customize the Flipper setup. 30 | */ 31 | public class ReactNativeFlipper { 32 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 33 | if (FlipperUtils.shouldEnableFlipper(context)) { 34 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 35 | 36 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 37 | client.addPlugin(new DatabasesFlipperPlugin(context)); 38 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 39 | client.addPlugin(CrashReporterPlugin.getInstance()); 40 | 41 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 42 | NetworkingModule.setCustomClientBuilder( 43 | new NetworkingModule.CustomClientBuilder() { 44 | @Override 45 | public void apply(OkHttpClient.Builder builder) { 46 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 47 | } 48 | }); 49 | client.addPlugin(networkFlipperPlugin); 50 | client.start(); 51 | 52 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 53 | // Hence we run if after all native modules have been initialized 54 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 55 | if (reactContext == null) { 56 | reactInstanceManager.addReactInstanceEventListener( 57 | new ReactInstanceEventListener() { 58 | @Override 59 | public void onReactContextInitialized(ReactContext reactContext) { 60 | reactInstanceManager.removeReactInstanceEventListener(this); 61 | reactContext.runOnNativeModulesQueueThread( 62 | new Runnable() { 63 | @Override 64 | public void run() { 65 | client.addPlugin(new FrescoFlipperPlugin()); 66 | } 67 | }); 68 | } 69 | }); 70 | } else { 71 | client.addPlugin(new FrescoFlipperPlugin()); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /exampleExpo/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 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/java/com/keys/development/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.keys.development; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | 6 | import com.facebook.react.ReactActivity; 7 | import com.facebook.react.ReactActivityDelegate; 8 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 9 | import com.facebook.react.defaults.DefaultReactActivityDelegate; 10 | 11 | import expo.modules.ReactActivityDelegateWrapper; 12 | 13 | public class MainActivity extends ReactActivity { 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | // Set the theme to AppTheme BEFORE onCreate to support 17 | // coloring the background, status bar, and navigation bar. 18 | // This is required for expo-splash-screen. 19 | setTheme(R.style.AppTheme); 20 | super.onCreate(null); 21 | } 22 | 23 | /** 24 | * Returns the name of the main component registered from JavaScript. 25 | * This is used to schedule rendering of the component. 26 | */ 27 | @Override 28 | protected String getMainComponentName() { 29 | return "main"; 30 | } 31 | 32 | /** 33 | * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link 34 | * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React 35 | * (aka React 18) with two boolean flags. 36 | */ 37 | @Override 38 | protected ReactActivityDelegate createReactActivityDelegate() { 39 | return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate( 40 | this, 41 | getMainComponentName(), 42 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 43 | DefaultNewArchitectureEntryPoint.getFabricEnabled())); 44 | } 45 | 46 | /** 47 | * Align the back button behavior with Android S 48 | * where moving root activities to background instead of finishing activities. 49 | * @see onBackPressed 50 | */ 51 | @Override 52 | public void invokeDefaultOnBackPressed() { 53 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { 54 | if (!moveTaskToBack(false)) { 55 | // For non-root activities, use the default implementation to finish them. 56 | super.invokeDefaultOnBackPressed(); 57 | } 58 | return; 59 | } 60 | 61 | // Use the default back button implementation on Android S 62 | // because it's doing more than {@link Activity#moveTaskToBack} in fact. 63 | super.invokeDefaultOnBackPressed(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/java/com/keys/development/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.keys.development; 2 | 3 | import android.app.Application; 4 | import android.content.res.Configuration; 5 | import androidx.annotation.NonNull; 6 | 7 | import com.facebook.react.PackageList; 8 | import com.facebook.react.ReactApplication; 9 | import com.facebook.react.ReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.config.ReactFeatureFlags; 12 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 13 | import com.facebook.react.defaults.DefaultReactNativeHost; 14 | import com.facebook.soloader.SoLoader; 15 | 16 | import expo.modules.ApplicationLifecycleDispatcher; 17 | import expo.modules.ReactNativeHostWrapper; 18 | 19 | import java.util.List; 20 | 21 | public class MainApplication extends Application implements ReactApplication { 22 | 23 | private final ReactNativeHost mReactNativeHost = 24 | new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) { 25 | @Override 26 | public boolean getUseDeveloperSupport() { 27 | return BuildConfig.DEBUG; 28 | } 29 | 30 | @Override 31 | protected List getPackages() { 32 | @SuppressWarnings("UnnecessaryLocalVariable") 33 | List packages = new PackageList(this).getPackages(); 34 | // Packages that cannot be autolinked yet can be added manually here, for example: 35 | // packages.add(new MyReactNativePackage()); 36 | return packages; 37 | } 38 | 39 | @Override 40 | protected String getJSMainModuleName() { 41 | return ".expo/.virtual-metro-entry"; 42 | } 43 | 44 | @Override 45 | protected boolean isNewArchEnabled() { 46 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 47 | } 48 | 49 | @Override 50 | protected Boolean isHermesEnabled() { 51 | return BuildConfig.IS_HERMES_ENABLED; 52 | } 53 | }); 54 | 55 | @Override 56 | public ReactNativeHost getReactNativeHost() { 57 | return mReactNativeHost; 58 | } 59 | 60 | @Override 61 | public void onCreate() { 62 | super.onCreate(); 63 | SoLoader.init(this, /* native exopackage */ false); 64 | if (!BuildConfig.REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS) { 65 | ReactFeatureFlags.unstable_useRuntimeSchedulerAlways = false; 66 | } 67 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 68 | // If you opted-in for the New Architecture, we load the native entry point for this app. 69 | DefaultNewArchitectureEntryPoint.load(); 70 | } 71 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 72 | ApplicationLifecycleDispatcher.onApplicationCreate(this); 73 | } 74 | 75 | @Override 76 | public void onConfigurationChanged(@NonNull Configuration newConfig) { 77 | super.onConfigurationChanged(newConfig); 78 | ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable-hdpi/splashscreen_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/drawable-hdpi/splashscreen_image.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable-mdpi/splashscreen_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/drawable-mdpi/splashscreen_image.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable-xhdpi/splashscreen_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/drawable-xhdpi/splashscreen_image.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable-xxhdpi/splashscreen_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/drawable-xxhdpi/splashscreen_image.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable-xxxhdpi/splashscreen_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/drawable-xxxhdpi/splashscreen_image.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/drawable/splashscreen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff 3 | #ffffff 4 | #023c69 5 | #ffffff 6 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | dev app 3 | contain 4 | false 5 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 17 | -------------------------------------------------------------------------------- /exampleExpo/android/app/src/release/java/com/keys/development/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.keys.development; 8 | 9 | import android.content.Context; 10 | import com.facebook.react.ReactInstanceManager; 11 | 12 | /** 13 | * Class responsible of loading Flipper inside your React Native application. This is the release 14 | * flavor of it so it's empty as we don't want to load Flipper. 15 | */ 16 | public class ReactNativeFlipper { 17 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 18 | // Do nothing as we don't want to initialize Flipper on Release. 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /exampleExpo/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = findProperty('android.buildToolsVersion') ?: '33.0.0' 6 | minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21') 7 | compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '33') 8 | targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '33') 9 | kotlinVersion = findProperty('android.kotlinVersion') ?: '1.8.10' 10 | frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0' 11 | 12 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. 13 | ndkVersion = "23.1.7779620" 14 | } 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | dependencies { 20 | classpath('com.android.tools.build:gradle:7.4.2') 21 | classpath('com.facebook.react:react-native-gradle-plugin') 22 | } 23 | } 24 | 25 | allprojects { 26 | repositories { 27 | maven { 28 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 29 | url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android')) 30 | } 31 | maven { 32 | // Android JSC is installed from npm 33 | url(new File(['node', '--print', "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), '../dist')) 34 | } 35 | 36 | google() 37 | mavenCentral() 38 | maven { url 'https://www.jitpack.io' } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /exampleExpo/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 | # Automatically convert third-party libraries to use AndroidX 26 | android.enableJetifier=true 27 | 28 | # Version of flipper SDK to use with React Native 29 | FLIPPER_VERSION=0.182.0 30 | 31 | # Use this property to specify which architecture you want to build. 32 | # You can also override it from the CLI using 33 | # ./gradlew -PreactNativeArchitectures=x86_64 34 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 35 | 36 | # Use this property to enable support to the new architecture. 37 | # This will allow you to use TurboModules and the Fabric render in 38 | # your application. You should enable this flag either if you want 39 | # to write custom TurboModules/Fabric components OR use libraries that 40 | # are providing them. 41 | newArchEnabled=false 42 | 43 | # Use this property to enable or disable the Hermes JS engine. 44 | # If set to false, you will be using JSC instead. 45 | hermesEnabled=true 46 | 47 | # Enable GIF support in React Native images (~200 B increase) 48 | expo.gif.enabled=true 49 | # Enable webp support in React Native images (~85 KB increase) 50 | expo.webp.enabled=true 51 | # Enable animated webp support (~3.4 MB increase) 52 | # Disabled by default because iOS doesn't support animated webp 53 | expo.webp.animated=false 54 | 55 | # Enable network inspector 56 | EX_DEV_CLIENT_NETWORK_INSPECTOR=true 57 | 58 | android.packagingOptions.pickFirsts=**/libcrypto.so -------------------------------------------------------------------------------- /exampleExpo/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /exampleExpo/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /exampleExpo/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if %ERRORLEVEL% equ 0 goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if %ERRORLEVEL% equ 0 goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /exampleExpo/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'dev app' 2 | 3 | apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); 4 | useExpoModules() 5 | 6 | apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); 7 | applyNativeModulesSettingsGradle(settings) 8 | 9 | include ':app' 10 | includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile()) 11 | -------------------------------------------------------------------------------- /exampleExpo/app.config.js: -------------------------------------------------------------------------------- 1 | const APP_VARIANT = process.env.APP_VARIANT || 'development'; 2 | 3 | const data = { 4 | development: { 5 | appName: 'dev app', 6 | bundleIdentifier: 'com.keys.development', 7 | package: 'com.keys.development', 8 | }, 9 | staging: { 10 | appName: 'staging app', 11 | bundleIdentifier: 'com.keys.staging', 12 | package: 'com.keys.staging', 13 | }, 14 | production: { 15 | appName: 'prod app', 16 | bundleIdentifier: 'com.keys.production', 17 | package: 'com.keys.production', 18 | }, 19 | }; 20 | 21 | export default { 22 | expo: { 23 | name: data[APP_VARIANT].appName, 24 | slug: 'example', 25 | version: '1.0.0', 26 | orientation: 'portrait', 27 | icon: './assets/icon.png', 28 | userInterfaceStyle: 'automatic', 29 | splash: { 30 | image: './assets/splash.png', 31 | resizeMode: 'contain', 32 | backgroundColor: '#ffffff', 33 | }, 34 | assetBundlePatterns: ['**/*'], 35 | ios: { 36 | supportsTablet: true, 37 | bundleIdentifier: data[APP_VARIANT].bundleIdentifier, 38 | }, 39 | android: { 40 | package: data[APP_VARIANT].package, 41 | adaptiveIcon: { 42 | foregroundImage: './assets/adaptive-icon.png', 43 | backgroundColor: '#ffffff', 44 | }, 45 | }, 46 | web: { 47 | favicon: './assets/favicon.png', 48 | }, 49 | plugins: [ 50 | [ 51 | '../app.plugin.js', 52 | { 53 | android: { 54 | defaultKeyFile: 'keys.production.json', 55 | }, 56 | ios: { 57 | defaultKeyFile: 'keys.production.json', 58 | }, 59 | IS_EXAMPLE: true, 60 | }, 61 | ], 62 | ], 63 | }, 64 | }; 65 | -------------------------------------------------------------------------------- /exampleExpo/assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/assets/adaptive-icon.png -------------------------------------------------------------------------------- /exampleExpo/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/assets/favicon.png -------------------------------------------------------------------------------- /exampleExpo/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/assets/icon.png -------------------------------------------------------------------------------- /exampleExpo/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/assets/splash.png -------------------------------------------------------------------------------- /exampleExpo/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = function (api) { 5 | api.cache(true); 6 | 7 | return { 8 | presets: ['babel-preset-expo'], 9 | plugins: [ 10 | [ 11 | 'module-resolver', 12 | { 13 | extensions: ['.tsx', '.ts', '.js', '.json'], 14 | alias: { 15 | // For development, we want to alias the library to the source 16 | [pak.name]: path.join(__dirname, '..', pak.source), 17 | }, 18 | }, 19 | ], 20 | ], 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /exampleExpo/eas.json: -------------------------------------------------------------------------------- 1 | { 2 | "cli": { 3 | "version": ">= 3.0.0" 4 | }, 5 | "build": { 6 | "development": { 7 | "developmentClient": true, 8 | "env": { 9 | "APP_VARIANT": "development", 10 | "KEYSFILE": "keys.development.json" 11 | }, 12 | "distribution": "internal", 13 | "android": { 14 | "gradleCommand": ":app:assembleDevelopmentDebug" 15 | }, 16 | "ios": { 17 | "buildConfiguration": "Debug", 18 | "scheme": "Development" 19 | } 20 | }, 21 | "staging": { 22 | "env": { 23 | "APP_VARIANT": "staging", 24 | "KEYSFILE": "keys.staging.json" 25 | }, 26 | "distribution": "internal", 27 | "android": { 28 | "gradleCommand": ":app:assembleStagingRelease" 29 | }, 30 | "ios": { 31 | "buildConfiguration": "Release", 32 | "scheme": "Staging" 33 | } 34 | }, 35 | "production": { 36 | "env": { 37 | "APP_VARIANT": "production", 38 | "KEYSFILE": "keys.production.json" 39 | }, 40 | "distribution": "internal", 41 | "android": { 42 | "gradleCommand": ":app:assembleProductionRelease" 43 | }, 44 | "ios": { 45 | "buildConfiguration": "Release", 46 | "scheme": "Production" 47 | } 48 | }, 49 | "preview": { 50 | "distribution": "internal" 51 | }, 52 | }, 53 | "submit": { 54 | "production": {} 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /exampleExpo/ios/.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 | project.xcworkspace 24 | .xcode.env.local 25 | 26 | # Bundle artifacts 27 | *.jsbundle 28 | 29 | # CocoaPods 30 | /Pods/ 31 | -------------------------------------------------------------------------------- /exampleExpo/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /exampleExpo/ios/Podfile: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") 2 | require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods") 3 | 4 | require 'json' 5 | podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {} 6 | 7 | ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0' 8 | ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] 9 | 10 | platform :ios, podfile_properties['ios.deploymentTarget'] || '13.0' 11 | install! 'cocoapods', 12 | :deterministic_uuids => false 13 | 14 | prepare_react_native_project! 15 | 16 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. 17 | # because `react-native-flipper` depends on (FlipperKit,...), which will be excluded. To fix this, 18 | # you can also exclude `react-native-flipper` in `react-native.config.js` 19 | # 20 | # ```js 21 | # module.exports = { 22 | # dependencies: { 23 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), 24 | # } 25 | # } 26 | # ``` 27 | flipper_config = FlipperConfiguration.disabled 28 | if ENV['NO_FLIPPER'] == '1' then 29 | # Explicitly disabled through environment variables 30 | flipper_config = FlipperConfiguration.disabled 31 | elsif podfile_properties.key?('ios.flipper') then 32 | # Configure Flipper in Podfile.properties.json 33 | if podfile_properties['ios.flipper'] == 'true' then 34 | flipper_config = FlipperConfiguration.enabled(["Debug", "Release"]) 35 | elsif podfile_properties['ios.flipper'] != 'false' then 36 | flipper_config = FlipperConfiguration.enabled(["Debug", "Release"], { 'Flipper' => podfile_properties['ios.flipper'] }) 37 | end 38 | end 39 | 40 | target 'devapp' do 41 | use_expo_modules! 42 | config = use_native_modules! 43 | 44 | use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] 45 | use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS'] 46 | 47 | # Flags change depending on the env values. 48 | flags = get_default_flags() 49 | 50 | use_react_native!( 51 | :path => config[:reactNativePath], 52 | :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes', 53 | :fabric_enabled => flags[:fabric_enabled], 54 | # An absolute path to your application root. 55 | :app_path => "#{Pod::Config.instance.installation_root}/..", 56 | # Note that if you have use_frameworks! enabled, Flipper will not work if enabled 57 | :flipper_configuration => flipper_config 58 | ) 59 | 60 | post_install do |installer| 61 | react_native_post_install( 62 | installer, 63 | config[:reactNativePath], 64 | :mac_catalyst_enabled => false 65 | ) 66 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 67 | 68 | # This is necessary for Xcode 14, because it signs resource bundles by default 69 | # when building for devices. 70 | installer.target_installation_results.pod_target_installation_results 71 | .each do |pod_name, target_installation_result| 72 | target_installation_result.resource_bundle_targets.each do |resource_bundle_target| 73 | resource_bundle_target.build_configurations.each do |config| 74 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' 75 | end 76 | end 77 | end 78 | end 79 | 80 | post_integrate do |installer| 81 | begin 82 | expo_patch_react_imports!(installer) 83 | rescue => e 84 | Pod::UI.warn e 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /exampleExpo/ios/Podfile.properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo.jsEngine": "hermes", 3 | "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true" 4 | } 5 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp.xcodeproj/xcshareddata/xcschemes/devapp.xcscheme: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface AppDelegate : EXAppDelegateWrapper 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | #import 5 | 6 | @implementation AppDelegate 7 | 8 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 9 | { 10 | self.moduleName = @"main"; 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 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 20 | { 21 | #if DEBUG 22 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"]; 23 | #else 24 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 25 | #endif 26 | } 27 | 28 | // Linking API 29 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { 30 | return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options]; 31 | } 32 | 33 | // Universal Links 34 | - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler { 35 | BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; 36 | return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result; 37 | } 38 | 39 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries 40 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 41 | { 42 | return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; 43 | } 44 | 45 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries 46 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error 47 | { 48 | return [super application:application didFailToRegisterForRemoteNotificationsWithError:error]; 49 | } 50 | 51 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries 52 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 53 | { 54 | return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/ios/devapp/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "filename": "App-Icon-1024x1024@1x.png", 5 | "idiom": "universal", 6 | "platform": "ios", 7 | "size": "1024x1024" 8 | } 9 | ], 10 | "info": { 11 | "version": 1, 12 | "author": "expo" 13 | } 14 | } -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "expo" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/SplashScreen.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "universal", 5 | "filename": "image.png", 6 | "scale": "1x" 7 | }, 8 | { 9 | "idiom": "universal", 10 | "scale": "2x" 11 | }, 12 | { 13 | "idiom": "universal", 14 | "scale": "3x" 15 | } 16 | ], 17 | "info": { 18 | "version": 1, 19 | "author": "expo" 20 | } 21 | } -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/SplashScreen.imageset/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/ios/devapp/Images.xcassets/SplashScreen.imageset/image.png -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/SplashScreenBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "universal", 5 | "filename": "image.png", 6 | "scale": "1x" 7 | }, 8 | { 9 | "idiom": "universal", 10 | "scale": "2x" 11 | }, 12 | { 13 | "idiom": "universal", 14 | "scale": "3x" 15 | } 16 | ], 17 | "info": { 18 | "version": 1, 19 | "author": "expo" 20 | } 21 | } -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Images.xcassets/SplashScreenBackground.imageset/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/exampleExpo/ios/devapp/Images.xcassets/SplashScreenBackground.imageset/image.png -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | dev app 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 21 | CFBundleShortVersionString 22 | 1.0.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | 28 | CFBundleURLSchemes 29 | 30 | com.keys.development 31 | 32 | 33 | 34 | CFBundleVersion 35 | 1 36 | LSRequiresIPhoneOS 37 | 38 | NSAppTransportSecurity 39 | 40 | NSAllowsArbitraryLoads 41 | 42 | NSExceptionDomains 43 | 44 | localhost 45 | 46 | NSExceptionAllowsInsecureHTTPLoads 47 | 48 | 49 | 50 | 51 | UILaunchStoryboardName 52 | SplashScreen 53 | UIRequiredDeviceCapabilities 54 | 55 | armv7 56 | 57 | UIRequiresFullScreen 58 | 59 | UIStatusBarStyle 60 | UIStatusBarStyleDefault 61 | UISupportedInterfaceOrientations 62 | 63 | UIInterfaceOrientationPortrait 64 | UIInterfaceOrientationPortraitUpsideDown 65 | 66 | UISupportedInterfaceOrientations~ipad 67 | 68 | UIInterfaceOrientationPortrait 69 | UIInterfaceOrientationPortraitUpsideDown 70 | UIInterfaceOrientationLandscapeLeft 71 | UIInterfaceOrientationLandscapeRight 72 | 73 | UIUserInterfaceStyle 74 | Automatic 75 | UIViewControllerBasedStatusBarAppearance 76 | 77 | 78 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/SplashScreen.storyboard: -------------------------------------------------------------------------------- 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 | 50 | 51 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/Supporting/Expo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | EXUpdatesCheckOnLaunch 6 | ALWAYS 7 | EXUpdatesEnabled 8 | 9 | EXUpdatesLaunchWaitMs 10 | 0 11 | EXUpdatesSDKVersion 12 | 49.0.0 13 | 14 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/devapp-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/devapp.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /exampleExpo/ios/devapp/noop-file.swift: -------------------------------------------------------------------------------- 1 | // 2 | // @generated 3 | // A blank Swift file must be created for native modules with Swift files to work correctly. 4 | // 5 | -------------------------------------------------------------------------------- /exampleExpo/keys.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "secure": { 3 | "secure1": "dev secure1 value", 4 | "secure2": "dev secure2 value", 5 | "secure3": "dev secure3 3value test1", 6 | "GOOGLE_API": "GOOGLE_API", 7 | "BRANCH_API": "BRANCH_API" 8 | }, 9 | "public": { 10 | "APP_NAME": "dev RNKEYS 11 testing111", 11 | "BUNDLE_ID": "com.example.rnkeys.dev", 12 | "ANDROID_CODE": "50", 13 | "PACKAGE_ID": "com.example.rnkeys.dev", 14 | "public1": "dev numan", 15 | "public2": "dev usman" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exampleExpo/keys.production.json: -------------------------------------------------------------------------------- 1 | { 2 | "secure": { 3 | "secure1": "prod secure1 value", 4 | "secure2": "prod secure2 value", 5 | "secure3": "prod secure3 value", 6 | "GOOGLE_API": "ABCD", 7 | "BRANCH_API": "ABCDEF" 8 | }, 9 | "public": { 10 | "APP_NAME": "prod RNKEYS", 11 | "BUNDLE_ID": "com.example.rnkeys.prod", 12 | "ANDROID_CODE": "50", 13 | "PACKAGE_ID": "com.example.rnkeys.prod", 14 | "public1": "prod numan", 15 | "public2": "prod usman" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exampleExpo/keys.staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "secure": { 3 | "secure1": "staging secure1 value", 4 | "secure2": "staging secure2 value", 5 | "secure3": "staging secure3 value", 6 | "GOOGLE_API": "ABCD", 7 | "BRANCH_API": "ABCDEF" 8 | }, 9 | "public": { 10 | "APP_NAME": "staging RNKEYS", 11 | "BUNDLE_ID": "com.example.rnkeys.staging", 12 | "ANDROID_CODE": "50", 13 | "PACKAGE_ID": "com.example.rnkeys.staging", 14 | "public1": "staging numan", 15 | "public2": "staging usman" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exampleExpo/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const escape = require('escape-string-regexp'); 3 | const { getDefaultConfig } = require('@expo/metro-config'); 4 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 5 | const pak = require('../package.json'); 6 | 7 | const root = path.resolve(__dirname, '..'); 8 | const modules = Object.keys({ ...pak.peerDependencies }); 9 | 10 | const defaultConfig = getDefaultConfig(__dirname); 11 | 12 | /** 13 | * Metro configuration 14 | * https://facebook.github.io/metro/docs/configuration 15 | * 16 | * @type {import('metro-config').MetroConfig} 17 | */ 18 | const config = { 19 | ...defaultConfig, 20 | 21 | projectRoot: __dirname, 22 | watchFolders: [root], 23 | 24 | // We need to make sure that only one version is loaded for peerDependencies 25 | // So we block them at the root, and alias them to the versions in example's node_modules 26 | resolver: { 27 | ...defaultConfig.resolver, 28 | 29 | blacklistRE: exclusionList( 30 | modules.map( 31 | (m) => 32 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 33 | ) 34 | ), 35 | 36 | extraNodeModules: modules.reduce((acc, name) => { 37 | acc[name] = path.join(__dirname, 'node_modules', name); 38 | return acc; 39 | }, {}), 40 | }, 41 | }; 42 | 43 | module.exports = config; 44 | -------------------------------------------------------------------------------- /exampleExpo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exampleexpo", 3 | "version": "1.0.0", 4 | "main": "node_modules/expo/AppEntry.js", 5 | "scripts": { 6 | "start": "expo start", 7 | "android": "expo run:android", 8 | "androidProd": "npx expo run:android --variant production", 9 | "ios": "expo run:ios", 10 | "web": "expo start --web", 11 | "dev:android": "KEYSFILE=keys.development.json npx expo run:android", 12 | "staging:android": "KEYSFILE=keys.staging.json npx expo run:android", 13 | "prod:android": "KEYSFILE=keys.production.json npx expo run:android", 14 | "dev:ios": "KEYSFILE=keys.development.json npx expo run:ios", 15 | "staging:ios": "KEYSFILE=keys.staging.json npx expo run:ios", 16 | "prod:ios": "KEYSFILE=keys.production.json npx expo run:ios" 17 | }, 18 | "dependencies": { 19 | "expo": "49.0.13", 20 | "expo-splash-screen": "~0.20.4", 21 | "expo-status-bar": "~1.6.0", 22 | "react": "18.2.0", 23 | "react-dom": "18.2.0", 24 | "react-native": "0.72.5", 25 | "react-native-web": "~0.19.6" 26 | }, 27 | "devDependencies": { 28 | "@babel/core": "^7.20.0", 29 | "@expo/config-plugins": "^7.2.5", 30 | "@expo/webpack-config": "^19.0.0", 31 | "@types/react": "^18.2.17", 32 | "@types/react-dom": "~18.0.10", 33 | "@types/react-native": "^0.72.2", 34 | "babel-loader": "^8.1.0", 35 | "babel-plugin-module-resolver": "^5.0.0" 36 | }, 37 | "private": true 38 | } 39 | -------------------------------------------------------------------------------- /exampleExpo/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /exampleExpo/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { StyleSheet, View, Text } from 'react-native'; 3 | import RNKeys from 'react-native-keys'; 4 | export default function App() { 5 | const [jniValue, setJniValue] = useState(''); 6 | const [publicValue, setPublicValue] = useState(''); 7 | useEffect(() => { 8 | const value1 = RNKeys.secureFor('secure3'); 9 | console.log(value1, 'value1'); 10 | setJniValue(value1); 11 | const value2 = RNKeys.APP_NAME; 12 | setPublicValue(value2); 13 | }, []); 14 | return ( 15 | 16 | KEY FROM SECURE (JNI): {jniValue} 17 | KEY FROM PUBLIC: {publicValue} 18 | 19 | ); 20 | } 21 | 22 | const styles = StyleSheet.create({ 23 | container: { 24 | flex: 1, 25 | alignItems: 'center', 26 | justifyContent: 'center', 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /exampleExpo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | // Avoid expo-cli auto-generating a tsconfig 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /exampleExpo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const createExpoWebpackConfigAsync = require('@expo/webpack-config'); 3 | const { resolver } = require('./metro.config'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | const node_modules = path.join(__dirname, 'node_modules'); 7 | 8 | module.exports = async function (env, argv) { 9 | const config = await createExpoWebpackConfigAsync(env, argv); 10 | 11 | config.module.rules.push({ 12 | test: /\.(js|jsx|ts|tsx)$/, 13 | include: path.resolve(root, 'src'), 14 | use: 'babel-loader', 15 | }); 16 | 17 | // We need to make sure that only one version is loaded for peerDependencies 18 | // So we alias them to the versions in example's node_modules 19 | Object.assign(config.resolve.alias, { 20 | ...resolver.extraNodeModules, 21 | 'react-native-web': path.join(node_modules, 'react-native-web'), 22 | }); 23 | 24 | return config; 25 | }; 26 | -------------------------------------------------------------------------------- /ios/GeneratedDotEnv.m: -------------------------------------------------------------------------------- 1 | #define DOT_ENV @{ @"APP_NAME":@"prod RNKEYS",@"BUNDLE_ID":@"com.example.rnkeys.prod",@"ANDROID_CODE":@"50",@"PACKAGE_ID":@"com.example.rnkeys.prod",@"public1":@"prod numan",@"public2":@"prod usman" }; -------------------------------------------------------------------------------- /ios/Keys.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | #endif 3 | 4 | #ifdef RCT_NEW_ARCH_ENABLED 5 | #import 6 | 7 | @interface Keys : NSObject 8 | #else 9 | #import 10 | 11 | @interface Keys : NSObject 12 | #endif 13 | 14 | + (NSString *)secureFor:(NSString *)key; 15 | + (NSDictionary *)public_keys; 16 | + (NSString *)publicFor:(NSString *)key; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ios/Keys.mm: -------------------------------------------------------------------------------- 1 | #import "Keys.h" 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import "YeetJSIUtils.h" 7 | #import 8 | 9 | #import "crypto.h" 10 | #import "GeneratedDotEnv.m" 11 | #import "privateKey.m" 12 | 13 | using namespace facebook::jsi; 14 | using namespace std; 15 | 16 | @implementation Keys 17 | 18 | @synthesize bridge = _bridge; 19 | @synthesize methodQueue = _methodQueue; 20 | 21 | RCT_EXPORT_MODULE() 22 | 23 | + (BOOL)requiresMainQueueSetup { 24 | return YES; 25 | } 26 | 27 | // Installing JSI Bindings 28 | RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) 29 | { 30 | RCTBridge* bridge = [RCTBridge currentBridge]; 31 | RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge; 32 | if (cxxBridge == nil) { 33 | return @false; 34 | } 35 | 36 | auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime; 37 | if (jsiRuntime == nil) { 38 | return @false; 39 | } 40 | 41 | auto& runtime = *jsiRuntime; 42 | 43 | auto secureFor = Function::createFromHostFunction(runtime, 44 | PropNameID::forAscii(runtime, 45 | "secureFor"), 46 | 1, 47 | [](Runtime &runtime, 48 | const Value &thisValue, 49 | const Value *arguments, 50 | size_t count) -> Value { 51 | NSString *key = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); 52 | NSString *value = [Keys secureFor:key]; 53 | return Value(runtime, convertNSStringToJSIString(runtime, value)); 54 | }); 55 | 56 | runtime.global().setProperty(runtime, "secureFor", std::move(secureFor)); 57 | 58 | 59 | auto publicKeys = Function::createFromHostFunction(runtime, 60 | PropNameID::forAscii(runtime, 61 | "publicKeys"), 62 | 0, 63 | [](Runtime &runtime, 64 | const Value &thisValue, 65 | const Value *arguments, 66 | size_t count) -> Value { 67 | NSDictionary *s = [Keys public_keys]; 68 | return Value(runtime, convertNSDictionaryToJSIObject(runtime, s)); 69 | 70 | }); 71 | 72 | runtime.global().setProperty(runtime, "publicKeys", std::move(publicKeys)); 73 | 74 | 75 | 76 | 77 | return @true; 78 | } 79 | 80 | 81 | + (NSString *)secureFor: (NSString *)key { 82 | @try { 83 | NSDictionary *privatesKeyEnv = PRIVATE_KEY; 84 | NSString *privateKey = [privatesKeyEnv objectForKey:@"privateKey"]; 85 | NSString* stringfyData = [NSString stringWithCString:Crypto().getJniJsonStringifyData([privateKey cStringUsingEncoding:NSUTF8StringEncoding]).c_str() encoding:[NSString defaultCStringEncoding]]; 86 | NSData *data = [stringfyData dataUsingEncoding:NSUTF8StringEncoding]; 87 | NSMutableDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; 88 | NSString *value =[s objectForKey:key]; 89 | return value; 90 | } 91 | @catch (NSException *exception) { 92 | return @""; 93 | } 94 | } 95 | 96 | + (NSDictionary *)public_keys { 97 | return (NSDictionary *)DOT_ENV; 98 | } 99 | 100 | + (NSString *)publicFor: (NSString *)key { 101 | NSString *value = (NSString *)[self.public_keys objectForKey:key]; 102 | return value; 103 | } 104 | 105 | // Don't compile this code when we build for the old architecture. 106 | #ifdef RCT_NEW_ARCH_ENABLED 107 | - (std::shared_ptr)getTurboModule: 108 | (const facebook::react::ObjCTurboModule::InitParams &)params { 109 | return std::make_shared(params); 110 | } 111 | #endif 112 | @end 113 | -------------------------------------------------------------------------------- /ios/YeetJSIUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // YeetJSIUTils.h 3 | // yeet 4 | // 5 | // Created by Jarred WSumner on 1/30/20. 6 | // Copyright © 2020 Facebook. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | using namespace facebook; 14 | /** 15 | * All static helper functions are ObjC++ specific. 16 | */ 17 | jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value); 18 | jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value); 19 | jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value); 20 | jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);; 21 | jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value); 22 | jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value); 23 | std::vector convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value); 24 | jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value); 25 | id convertJSIValueToObjCObject( 26 | jsi::Runtime &runtime, 27 | const jsi::Value &value); 28 | NSString* convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value); 29 | NSArray* convertJSIArrayToNSArray( 30 | jsi::Runtime &runtime, 31 | const jsi::Array &value); 32 | NSDictionary *convertJSIObjectToNSDictionary( 33 | jsi::Runtime &runtime, 34 | const jsi::Object &value); 35 | RCTResponseSenderBlock convertJSIFunctionToCallback( 36 | jsi::Runtime &runtime, 37 | const jsi::Function &value); 38 | id convertJSIValueToObjCObject( 39 | jsi::Runtime &runtime, 40 | const jsi::Value &value); 41 | RCTResponseSenderBlock convertJSIFunctionToCallback( 42 | jsi::Runtime &runtime, 43 | const jsi::Function &value); 44 | 45 | struct Promise { 46 | Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject); 47 | 48 | void resolve(const jsi::Value &result); 49 | void reject(const std::string &error); 50 | 51 | jsi::Runtime &runtime_; 52 | jsi::Function resolve_; 53 | jsi::Function reject_; 54 | }; 55 | 56 | using PromiseSetupFunctionType = 57 | std::function)>; 58 | jsi::Value createPromiseAsJSIValue( 59 | jsi::Runtime &rt, 60 | const PromiseSetupFunctionType func); 61 | -------------------------------------------------------------------------------- /keysAndroid.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const { 3 | getKeys, 4 | makeFileInAndroidMainAssetsFolder, 5 | getAndroidEnvironmentFile, 6 | generatePassword, 7 | encrypt, 8 | makeCppFileTemplate, 9 | splitPrivateKeyInto3ChunksOfArray, 10 | makeFileInCPPDir, 11 | genTSType, 12 | } = require('./src/util/common'); 13 | const { 14 | makeCryptographicModuleTemplateAndroid, 15 | } = require('./src/util/keysFilesTemplateAndroid'); 16 | 17 | const makeAndroidJnuFiles = () => { 18 | const KEYS_FILE_NAME = getAndroidEnvironmentFile(); 19 | const allKeys = getKeys(KEYS_FILE_NAME); 20 | const secureKeys = allKeys.secure; 21 | const stringifyKeys = JSON.stringify(secureKeys); 22 | const password = generatePassword(); 23 | const privateKey = encrypt(stringifyKeys, password); 24 | const privateKeyIn3Chunks = splitPrivateKeyInto3ChunksOfArray(privateKey); 25 | const cppFileContent = makeCppFileTemplate(privateKeyIn3Chunks, password); 26 | const isDoneCryptoCppFile = makeFileInCPPDir(cppFileContent, 'crypto.cpp'); 27 | 28 | const halfKey = privateKey.substr(privateKey.length / 2); 29 | const cryptographicModuleFileContent = 30 | makeCryptographicModuleTemplateAndroid(halfKey); 31 | const isDoneAddedPrivateKey = makeFileInAndroidMainAssetsFolder( 32 | cryptographicModuleFileContent, 33 | 'PrivateKey.java' 34 | ); 35 | genTSType(allKeys); 36 | console.info('react-native-keys', { 37 | isDoneCryptoCppFile, 38 | isDoneAddedPrivateKey, 39 | }); 40 | }; 41 | makeAndroidJnuFiles(); 42 | -------------------------------------------------------------------------------- /keysIOS.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const { 3 | getKeys, 4 | makeFileInIosDir, 5 | makeFileInCPPDir, 6 | getIosEnvironmentFile, 7 | makeFileInProjectDirectoryIos, 8 | splitPrivateKeyInto3ChunksOfArray, 9 | makeCppFileTemplate, 10 | generatePassword, 11 | encrypt, 12 | genTSType, 13 | } = require('./src/util/common'); 14 | const { 15 | makePrivateKeyTemplateIOS, 16 | makeXcConfigFIlle, 17 | makeGeneratedDotEnvTemplateIOS, 18 | } = require('./src/util/keysFilesTemplateIos'); 19 | 20 | const makeIosJnuFiles = () => { 21 | const KEYS_FILE_NAME = getIosEnvironmentFile(); 22 | const allKeys = getKeys(KEYS_FILE_NAME); 23 | const secureKeys = allKeys.secure; 24 | const publicKeys = allKeys.public; 25 | const stringifyKeys = JSON.stringify(secureKeys); 26 | const password = generatePassword(); 27 | const privateKey = encrypt(stringifyKeys, password); 28 | const privateKeyIn3Chunks = splitPrivateKeyInto3ChunksOfArray(privateKey); 29 | const cppFileContent = makeCppFileTemplate(privateKeyIn3Chunks, password); 30 | const isDoneCryptoCppFile = makeFileInCPPDir(cppFileContent, 'crypto.cpp'); 31 | 32 | const halfKey = privateKey.substr(privateKey.length / 2); 33 | const generatedPrivateKeyContent = makePrivateKeyTemplateIOS({ 34 | privateKey: halfKey, 35 | }); 36 | const isGeneratedPrivateKeyFile = makeFileInIosDir( 37 | generatedPrivateKeyContent, 38 | 'privateKey.m' 39 | ); 40 | 41 | const xcConfigFileContent = makeXcConfigFIlle(publicKeys); 42 | const isDoneCreatedXCodeConfigFile = makeFileInProjectDirectoryIos( 43 | xcConfigFileContent, 44 | 'tmp.xcconfig' 45 | ); 46 | 47 | const generatedDotEnvContent = makeGeneratedDotEnvTemplateIOS(publicKeys); 48 | const isGeneratedDotEnvFile = makeFileInIosDir( 49 | generatedDotEnvContent, 50 | 'GeneratedDotEnv.m' 51 | ); 52 | genTSType(allKeys); 53 | console.info('react-native-keys', { 54 | isDoneCryptoCppFile, 55 | isGeneratedPrivateKeyFile, 56 | isDoneCreatedXCodeConfigFile, 57 | isGeneratedDotEnvFile, 58 | }); 59 | }; 60 | makeIosJnuFiles(); 61 | -------------------------------------------------------------------------------- /lefthook.yml: -------------------------------------------------------------------------------- 1 | # EXAMPLE USAGE: 2 | # 3 | # Refer for explanation to following link: 4 | # https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md 5 | # 6 | # pre-push: 7 | # commands: 8 | # packages-audit: 9 | # tags: frontend security 10 | # run: yarn audit 11 | # gems-audit: 12 | # tags: backend security 13 | # run: bundle audit 14 | # 15 | # pre-commit: 16 | # parallel: true 17 | # commands: 18 | # eslint: 19 | # glob: "*.{js,ts,jsx,tsx}" 20 | # run: yarn eslint {staged_files} 21 | # rubocop: 22 | # tags: backend style 23 | # glob: "*.rb" 24 | # exclude: "application.rb|routes.rb" 25 | # run: bundle exec rubocop --force-exclusion {all_files} 26 | # govet: 27 | # tags: backend style 28 | # files: git ls-files -m 29 | # glob: "*.go" 30 | # run: go vet {files} 31 | # scripts: 32 | # "hello.js": 33 | # runner: node 34 | # "any.go": 35 | # runner: go run 36 | -------------------------------------------------------------------------------- /media/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/media/1.png -------------------------------------------------------------------------------- /media/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/media/2.png -------------------------------------------------------------------------------- /media/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/media/3.png -------------------------------------------------------------------------------- /media/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/media/4.png -------------------------------------------------------------------------------- /media/flowchart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/media/flowchart.jpg -------------------------------------------------------------------------------- /media/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/numandev1/react-native-keys/71e98b851f05801559c4ca5b1a05d75d2e0a334b/media/keys.png -------------------------------------------------------------------------------- /plugin/src/android/addProductFlavors.ts: -------------------------------------------------------------------------------- 1 | import { ConfigPlugin, withAppBuildGradle } from '@expo/config-plugins'; 2 | 3 | import { PluginConfigType } from '../pluginConfig'; 4 | 5 | function convertToGradleProductFlavors(productFlavors: any) { 6 | let result = 'flavorDimensions "default"\nproductFlavors {\n'; 7 | 8 | for (const flavor in productFlavors) { 9 | if (productFlavors.hasOwnProperty(flavor)) { 10 | const applicationIdSuffix = productFlavors[flavor].applicationIdSuffix; 11 | result += ` ${flavor} {\n applicationIdSuffix "${applicationIdSuffix}"\n }\n`; 12 | } 13 | } 14 | 15 | result += '}'; 16 | 17 | return result; 18 | } 19 | 20 | function applyImplementation(appBuildGradle: string, productFlavors: string) { 21 | const productFlavorsRegex = 22 | /flavorDimensions.+\n+productFlavors\s*\{(?:[^{}]*|(?:(?:[^{}]*\{[^{}]*\})*[^{}]*))*\}\n/; 23 | appBuildGradle = appBuildGradle.replace(productFlavorsRegex, ''); 24 | // Make sure the project does not have the dependency already 25 | const signingConfigs = appBuildGradle.match( 26 | /signingConfigs\s*\{(?:[^{}]*|(?:(?:[^{}]*\{[^{}]*\})*[^{}]*))*\}/ 27 | )?.[0]; 28 | if (signingConfigs && appBuildGradle.includes(signingConfigs)) { 29 | return appBuildGradle.replace( 30 | signingConfigs, 31 | `${signingConfigs}\n${productFlavors}` 32 | ); 33 | } 34 | return appBuildGradle; 35 | } 36 | export const withAddProductFlavours: ConfigPlugin = ( 37 | config, 38 | props 39 | ) => { 40 | return withAppBuildGradle(config, (config) => { 41 | config.modResults.contents = applyImplementation( 42 | config.modResults.contents, 43 | //@ts-ignore 44 | convertToGradleProductFlavors(props.android.productFlavors) 45 | ); 46 | return config; 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /plugin/src/android/buildGradleProperties.ts: -------------------------------------------------------------------------------- 1 | import { ConfigPlugin, withGradleProperties } from '@expo/config-plugins'; 2 | 3 | import { PluginConfigType } from '../pluginConfig'; 4 | 5 | /** 6 | * Update `android/gradle.properties` 7 | */ 8 | 9 | const PICK_FIRST_KEY = 'android.packagingOptions.pickFirsts'; 10 | 11 | export const withAndroidGradleProperties: ConfigPlugin = ( 12 | config 13 | ) => { 14 | return withGradleProperties(config, (config) => { 15 | const pickFirst = config.modResults.find( 16 | (item: any) => item.key === PICK_FIRST_KEY 17 | ); 18 | if (!pickFirst) { 19 | config.modResults.push({ 20 | type: 'property', 21 | key: PICK_FIRST_KEY, 22 | value: '**/libcrypto.so', 23 | }); 24 | } 25 | 26 | return config; 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /plugin/src/android/buildscriptDependency.ts: -------------------------------------------------------------------------------- 1 | import { ConfigPlugin, withAppBuildGradle } from '@expo/config-plugins'; 2 | 3 | import { PluginConfigType } from '../pluginConfig'; 4 | 5 | /** 6 | * Update `/build.gradle` 7 | */ 8 | 9 | function applyImplementation( 10 | appBuildGradle: string, 11 | defaultKeyFile: string = 'keys.development.json', 12 | IS_EXAMPLE: string 13 | ) { 14 | const RnkeysImplementation = ` 15 | project.ext.IS_EXAMPLE = ${IS_EXAMPLE}; 16 | project.ext.DEFAULT_FILE_NAME = "${defaultKeyFile}" 17 | apply from: project(':react-native-keys').projectDir.getPath() + "/RNKeys.gradle" 18 | `; 19 | if (!appBuildGradle.includes('project.ext.DEFAULT_FILE_NAME')) { 20 | const enableProguardInReleaseBuildsLine = appBuildGradle.match( 21 | /def enableProguardInReleaseBuilds.+/ 22 | )?.[0]; 23 | if ( 24 | enableProguardInReleaseBuildsLine && 25 | appBuildGradle.includes(enableProguardInReleaseBuildsLine) 26 | ) { 27 | return appBuildGradle.replace( 28 | enableProguardInReleaseBuildsLine, 29 | `${enableProguardInReleaseBuildsLine}\n${RnkeysImplementation}` 30 | ); 31 | } 32 | } else { 33 | let regex = /(project\.ext\.DEFAULT_FILE_NAME\s*=\s*").*?"/; 34 | const projectExtKeyFilesLine = appBuildGradle.match(regex)?.[0]; 35 | if (projectExtKeyFilesLine) { 36 | return appBuildGradle.replace(regex, `$1${defaultKeyFile}"`); 37 | } 38 | } 39 | return appBuildGradle; 40 | } 41 | export const withAndroidBuildscriptDependency: ConfigPlugin< 42 | PluginConfigType 43 | > = (config, props) => { 44 | return withAppBuildGradle(config, (config) => { 45 | config.modResults.contents = applyImplementation( 46 | config.modResults.contents, 47 | props?.android?.defaultKeyFile, 48 | props?.IS_EXAMPLE ? 'true' : 'false' 49 | ); 50 | return config; 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /plugin/src/android/index.ts: -------------------------------------------------------------------------------- 1 | import { withAndroidBuildscriptDependency } from './buildscriptDependency'; 2 | import { withAndroidGradleProperties } from './buildGradleProperties'; 3 | import { withAddProductFlavours } from './addProductFlavors'; 4 | export { 5 | withAndroidBuildscriptDependency, 6 | withAndroidGradleProperties, 7 | withAddProductFlavours, 8 | }; 9 | -------------------------------------------------------------------------------- /plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ConfigPlugin, createRunOncePlugin } from '@expo/config-plugins'; 2 | 3 | import { 4 | withAndroidBuildscriptDependency, 5 | withAndroidGradleProperties, 6 | } from './android'; 7 | import { withPreActionScript } from './ios'; 8 | import { PluginConfigType } from './pluginConfig'; 9 | 10 | /** 11 | * A config plugin for configuring `react-native-keys` 12 | */ 13 | const withRnKeys: ConfigPlugin = (config, props) => { 14 | //Android; 15 | config = withAndroidBuildscriptDependency(config, props); 16 | config = withAndroidGradleProperties(config, props); 17 | 18 | // IOS 19 | config = withPreActionScript(config, props); 20 | 21 | return config; 22 | }; 23 | 24 | const pak = require('../../package.json'); 25 | export default createRunOncePlugin(withRnKeys, pak.name, pak.version); 26 | -------------------------------------------------------------------------------- /plugin/src/ios/index.ts: -------------------------------------------------------------------------------- 1 | import { withPreActionScript } from './preactionScript'; 2 | 3 | export { withPreActionScript }; 4 | -------------------------------------------------------------------------------- /plugin/src/ios/preactionScript.ts: -------------------------------------------------------------------------------- 1 | import { ConfigPlugin, withDangerousMod } from '@expo/config-plugins'; 2 | import { PluginConfigType } from '../pluginConfig'; 3 | import walkSync from 'walk-sync'; 4 | import NP from 'normalize-path'; 5 | import fs from 'fs'; 6 | import { parseStringPromise, Builder } from 'xml2js'; 7 | const normalizePath = process.platform === 'win32' ? NP : (p: any) => p; 8 | const iosXcodeproj = 'ios/*.xcodeproj/**/*.xcscheme'; 9 | 10 | const preAction = ( 11 | BuildableReference: any[], 12 | IS_EXAMPLE: boolean = false, 13 | defaultKeyFile: string = 'keys.development.json' 14 | ) => { 15 | return { 16 | PreActions: [ 17 | { 18 | ExecutionAction: [ 19 | { 20 | $: { 21 | ActionType: 22 | 'Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction', 23 | }, 24 | ActionContent: [ 25 | { 26 | $: { 27 | title: 'Run Script', 28 | scriptText: `${ 29 | IS_EXAMPLE 30 | ? 'exec > ${PROJECT_DIR}/prebuild.log 2>&1\nexport IS_EXAMPLE=TRUE\n' 31 | : '' 32 | }export DEFAULT_FILE_NAME=${defaultKeyFile}\n${ 33 | IS_EXAMPLE 34 | ? '"${SRCROOT}/../../keysIOS.js"' 35 | : '"${SRCROOT}/../node_modules/react-native-keys/keysIOS.js"' 36 | }`, 37 | }, 38 | EnvironmentBuildable: [ 39 | { 40 | BuildableReference: BuildableReference, 41 | }, 42 | ], 43 | }, 44 | ], 45 | }, 46 | ], 47 | }, 48 | ], 49 | }; 50 | }; 51 | 52 | export const withPreActionScript: ConfigPlugin = ( 53 | config, 54 | props 55 | ) => { 56 | return withDangerousMod(config, [ 57 | 'ios', 58 | async (dangerousConfig) => { 59 | try { 60 | const APP_PATH = process.cwd(); 61 | const paths = walkSync(normalizePath(APP_PATH), { 62 | globs: [iosXcodeproj], 63 | }); 64 | if (paths.length > 0) { 65 | const promises = paths.map(async (xcSchemePath) => { 66 | const xcSchemeContent = fs.readFileSync(xcSchemePath, { 67 | encoding: 'utf-8', 68 | }); 69 | const xcSchemeJson = await parseStringPromise(xcSchemeContent); 70 | let BuildAction = xcSchemeJson.Scheme.BuildAction; 71 | const BuildableReference = 72 | BuildAction[0].BuildActionEntries[0].BuildActionEntry[0] 73 | .BuildableReference; 74 | 75 | BuildAction[0] = { 76 | ...BuildAction[0], 77 | ...preAction( 78 | BuildableReference, 79 | props?.IS_EXAMPLE, 80 | props?.ios?.defaultKeyFile 81 | ), 82 | }; 83 | xcSchemeJson.Scheme.BuildAction = BuildAction; 84 | const builder = new Builder(); 85 | const xcSchemeXml = builder.buildObject(xcSchemeJson); 86 | fs.writeFileSync(xcSchemePath, xcSchemeXml); 87 | }); 88 | await Promise.all(promises); 89 | } 90 | } catch (error) { 91 | console.log(error, 'preactionScript <- react-native-keys'); 92 | } 93 | 94 | return dangerousConfig; 95 | }, 96 | ]); 97 | }; 98 | -------------------------------------------------------------------------------- /plugin/src/pluginConfig.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Configuration for `react-native-kyes` 3 | */ 4 | export interface PluginConfigType { 5 | ios: { 6 | defaultKeyFile?: string; 7 | }; 8 | android: { 9 | defaultKeyFile?: string; 10 | }; 11 | IS_EXAMPLE?: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "build", 5 | "rootDir": "src", 6 | "module": "CommonJS", 7 | "target": "ES2015", 8 | }, 9 | "include": [ 10 | "./src" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /react-native-keys.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' 5 | 6 | Pod::Spec.new do |s| 7 | s.name = "react-native-keys" 8 | s.version = package["version"] 9 | s.summary = package["description"] 10 | s.homepage = package["homepage"] 11 | s.license = package["license"] 12 | s.authors = package["author"] 13 | 14 | s.platforms = { :ios => "12.4" } 15 | s.source = { :git => "https://github.com/numandev1/react-native-keys.git", :tag => "#{s.version}" } 16 | 17 | s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{h,c,cpp}" 18 | # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. 19 | # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79. 20 | if respond_to?(:install_modules_dependencies, true) 21 | install_modules_dependencies(s) 22 | else 23 | s.dependency "React-Core" 24 | 25 | # Don't install the dependencies when we run `pod install` in the old architecture. 26 | if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then 27 | s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" 28 | s.pod_target_xcconfig = { 29 | "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", 30 | "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", 31 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" 32 | } 33 | s.dependency "React-Codegen" 34 | s.dependency "RCT-Folly" 35 | s.dependency "RCTRequired" 36 | s.dependency "RCTTypeSafety" 37 | s.dependency "ReactCommon/turbomodule/core" 38 | end 39 | end 40 | 41 | s.dependency "OpenSSL-Universal" 42 | end 43 | -------------------------------------------------------------------------------- /scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const child_process = require('child_process'); 3 | 4 | const root = path.resolve(__dirname, '..'); 5 | const args = process.argv.slice(2); 6 | const options = { 7 | cwd: process.cwd(), 8 | env: process.env, 9 | stdio: 'inherit', 10 | encoding: 'utf-8', 11 | }; 12 | 13 | let result; 14 | 15 | if (process.cwd() !== root || args.length) { 16 | // We're not in the root of the project, or additional arguments were passed 17 | // In this case, forward the command to `yarn` 18 | result = child_process.spawnSync('yarn', args, options); 19 | } else { 20 | // If `yarn` is run without arguments, perform bootstrap 21 | result = child_process.spawnSync('yarn', ['bootstrap'], options); 22 | } 23 | 24 | process.exitCode = result.status; 25 | -------------------------------------------------------------------------------- /src/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | it.todo('write a test'); 2 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { NativeModules, Platform } from 'react-native'; 2 | import type { KeyTurboSecuredType, KeyTurboType } from './type'; 3 | 4 | const LINKING_ERROR = 5 | `The package 'react-native-keys' doesn't seem to be linked. Make sure: \n\n` + 6 | Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) + 7 | '- You rebuilt the app after installing the package\n' + 8 | '- You are not using Expo Go\n'; 9 | 10 | // @ts-expect-error 11 | const isTurboModuleEnabled = global.__turboModuleProxy != null; 12 | 13 | // Keep this to sync auto install with the native code 14 | const KeysModule = isTurboModuleEnabled 15 | ? require('./spec/NativeKeys').default 16 | : NativeModules.Keys; 17 | 18 | const KeysTurboModule = KeysModule 19 | ? KeysModule 20 | : new Proxy( 21 | {}, 22 | { 23 | get() { 24 | throw new Error(LINKING_ERROR); 25 | }, 26 | } 27 | ); 28 | const installed = KeysTurboModule.install(); 29 | if (!installed) { 30 | throw new Error(LINKING_ERROR); 31 | } 32 | 33 | const KeysTurbo: { 34 | secureFor(key: keyof KeyTurboSecuredType): string; 35 | publicKeys(): KeyTurboType; 36 | } & KeyTurboType = global as any; 37 | 38 | Object.assign(KeysTurbo, { 39 | ...(Platform.OS === 'android' 40 | ? JSON.parse(KeysTurbo.publicKeys() as unknown as string) 41 | : KeysTurbo.publicKeys()), 42 | }); 43 | 44 | export default KeysTurbo; 45 | -------------------------------------------------------------------------------- /src/spec/NativeKeys.ts: -------------------------------------------------------------------------------- 1 | import type { TurboModule } from 'react-native'; 2 | import { TurboModuleRegistry } from 'react-native'; 3 | 4 | export interface Spec extends TurboModule { 5 | install(): boolean; 6 | } 7 | 8 | export default TurboModuleRegistry.getEnforcing('Keys'); 9 | -------------------------------------------------------------------------------- /src/type.ts: -------------------------------------------------------------------------------- 1 | // this file is auto generate, please do not modify 2 | export type KeyTurboType = { [key: string]: string }; 3 | 4 | export type KeyTurboSecuredType = { [key: string]: string }; 5 | -------------------------------------------------------------------------------- /src/util/keysFilesTemplateAndroid.js: -------------------------------------------------------------------------------- 1 | module.exports.makeCryptographicModuleTemplateAndroid = (key) => { 2 | return ` 3 | // this is autogenerated, dont change within it 4 | package com.reactnativekeysjsi; 5 | 6 | public class PrivateKey { 7 | public static String privatekey="${key}"; 8 | }`; 9 | }; 10 | -------------------------------------------------------------------------------- /src/util/keysFilesTemplateIos.js: -------------------------------------------------------------------------------- 1 | module.exports.makeXcConfigFIlle = (keys) => { 2 | try { 3 | let env_keys = []; 4 | for (let [key, value] of Object.entries(keys)) { 5 | env_keys.push(`${key}=${value}`); 6 | } 7 | return env_keys.join('\n'); 8 | } catch (error) { 9 | return ''; 10 | } 11 | }; 12 | 13 | module.exports.makeGeneratedDotEnvTemplateIOS = (keys) => { 14 | try { 15 | let env_keys = []; 16 | for (let [key, value] of Object.entries(keys)) { 17 | env_keys.push(`@"${key}":@"${value}"`); 18 | } 19 | const dotEnv = env_keys.join(); 20 | return `#define DOT_ENV @{ ${dotEnv} };`; 21 | } catch (error) { 22 | return `#define DOT_ENV @{};`; 23 | } 24 | }; 25 | 26 | module.exports.makePrivateKeyTemplateIOS = (keys) => { 27 | try { 28 | let env_keys = []; 29 | for (let [key, value] of Object.entries(keys)) { 30 | env_keys.push(`@"${key}":@"${value}"`); 31 | } 32 | const dotEnv = env_keys.join(); 33 | return `#define PRIVATE_KEY @{ ${dotEnv} };`; 34 | } catch (error) { 35 | return `#define PRIVATE_KEY @{};`; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": "./tsconfig", 4 | "exclude": ["example"] 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "react-native-keys": [ 6 | "./src/index.ts" 7 | ] 8 | }, 9 | "allowUnreachableCode": false, 10 | "allowUnusedLabels": false, 11 | "esModuleInterop": true, 12 | "verbatimModuleSyntax": false, 13 | "forceConsistentCasingInFileNames": true, 14 | "jsx": "react", 15 | "lib": [ 16 | "esnext" 17 | ], 18 | "module": "esnext", 19 | "moduleResolution": "node", 20 | "noFallthroughCasesInSwitch": true, 21 | "noImplicitReturns": true, 22 | "noImplicitUseStrict": false, 23 | "noStrictGenericChecks": false, 24 | "noUnusedLocals": true, 25 | "noUnusedParameters": true, 26 | "resolveJsonModule": true, 27 | "skipLibCheck": true, 28 | "strict": true, 29 | "target": "esnext", 30 | "noImplicitAny": true, 31 | "noEmitOnError": true, 32 | "removeComments": true 33 | } 34 | } 35 | --------------------------------------------------------------------------------