├── .gitattributes
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── enhancement.yml
├── PULL_REQUEST_TEMPLATE
└── workflows
│ ├── lint-md.yml
│ └── test.yml
├── .gitignore
├── CONTRIBUTING.md
├── README.md
├── apps
├── app
│ ├── .gitignore
│ ├── App.tsx
│ ├── app.config.js
│ ├── app.json
│ ├── assets
│ │ ├── adaptive-icon.png
│ │ ├── favicon.png
│ │ ├── icon.png
│ │ └── splash.png
│ ├── meta
│ │ └── screenshots
│ │ │ └── android
│ │ │ ├── en-US
│ │ │ └── APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png
│ │ │ ├── nl-NL
│ │ │ └── APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png
│ │ │ └── zh-CN
│ │ │ └── APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png
│ ├── package.json
│ ├── scripts
│ │ ├── build-detox-ios.sh
│ │ └── start-metro.sh
│ ├── src
│ │ ├── android-jsc-intl
│ │ │ └── App.tsx
│ │ └── react-native-adjust
│ │ │ └── App.tsx
│ └── tsconfig.json
├── apple-settings
│ ├── app.config.ts
│ ├── app.json
│ ├── index.js
│ ├── package.json
│ ├── src
│ │ ├── App.tsx
│ │ └── SettingsViews.tsx
│ └── tsconfig.json
├── ios-stickers
│ ├── app.config.js
│ ├── app.json
│ ├── assets
│ │ ├── imessage-icon.png
│ │ └── stickers
│ │ │ ├── annoyed.png
│ │ │ ├── avocool.png
│ │ │ ├── cant.png
│ │ │ ├── coder-girl.png
│ │ │ ├── cozzy copy.png
│ │ │ ├── cozzy.png
│ │ │ ├── crazy.png
│ │ │ ├── cuddle.png
│ │ │ ├── donno.png
│ │ │ ├── dork.png
│ │ │ ├── focus.png
│ │ │ └── teapot.png
│ ├── expo-template-bare-minimum-50.0.17.tgz
│ ├── index.js
│ ├── package.json
│ └── src
│ │ └── App.js
├── react-native-branch
│ ├── app.config.js
│ ├── app.json
│ ├── index.js
│ ├── package.json
│ └── src
│ │ └── App.js
├── react-native-dynamic-app-icon
│ ├── app.config.js
│ ├── app.json
│ ├── assets
│ │ └── icons
│ │ │ ├── autumn.png
│ │ │ ├── fall.png
│ │ │ ├── solstice.png
│ │ │ ├── spring.png
│ │ │ ├── summer.png
│ │ │ └── winter.png
│ ├── index.js
│ ├── package.json
│ ├── src
│ │ └── App.js
│ └── tsconfig.json
├── react-native-pdf
│ ├── app.config.js
│ ├── app.json
│ ├── index.js
│ ├── package.json
│ └── src
│ │ └── App.js
├── react-native-siri-shortcut
│ ├── app.config.js
│ ├── app.json
│ ├── index.js
│ ├── package.json
│ ├── src
│ │ ├── App.ios.tsx
│ │ └── App.tsx
│ └── tsconfig.json
└── react-native-webrtc
│ ├── app.config.js
│ ├── app.json
│ ├── index.js
│ ├── package.json
│ ├── src
│ └── App.js
│ └── tsconfig.json
├── fixtures
├── AppDelegate.mm
├── AppDelegate.swift
├── Podfile
├── README.md
├── app-Bridging-Header.h
├── app-build.gradle
├── build.gradle
└── getFixtures.ts
├── lerna.json
├── package.json
├── packages
├── android-jsc-intl
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── package.json
│ ├── src
│ │ └── withAndroidJscIntl.ts
│ └── tsconfig.json
├── apple-settings
│ ├── .eslintrc.js
│ ├── README.md
│ ├── __mocks__
│ │ ├── @expo
│ │ │ └── image-utils.ts
│ │ └── fs.ts
│ ├── jest.config.js
│ ├── jest
│ │ └── setup.js
│ ├── package.json
│ ├── src
│ │ ├── base-mods
│ │ │ ├── strings.ts
│ │ │ ├── withSettingsPlist.ts
│ │ │ ├── withSettingsStrings.ts
│ │ │ └── withXcparse.ts
│ │ ├── index.tsx
│ │ ├── models.ts
│ │ ├── schema
│ │ │ ├── SettingsPlist.json
│ │ │ └── SettingsPlist.ts
│ │ ├── static.ts
│ │ └── withLinkedSettingsBundle.ts
│ └── tsconfig.json
├── ios-stickers
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── __mocks__
│ │ ├── @expo
│ │ │ └── image-utils.ts
│ │ └── fs.ts
│ ├── jest.config.js
│ ├── jest
│ │ └── setup.js
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── fixtures
│ │ │ │ └── icon.png
│ │ │ ├── generateImessageIconsAsync.test.ts
│ │ │ └── withStickerPack-test.ts
│ │ ├── generateImessageIconsAsync.ts
│ │ ├── options.json
│ │ ├── withStickerAssets.ts
│ │ ├── withStickerInfoPlist.ts
│ │ ├── withStickerPack.ts
│ │ ├── withStickerXcodeTarget.ts
│ │ └── xcodeSticker.ts
│ └── tsconfig.json
├── react-native-adjust
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── package.json
│ ├── src
│ │ └── withReactNativeAdjust.ts
│ └── tsconfig.json
├── react-native-ble-plx
│ └── README.md
├── react-native-blob-util
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── withReactNativeBlobUtil-test.ts.snap
│ │ │ └── withReactNativeBlobUtil-test.ts
│ │ └── withReactNativeBlobUtil.ts
│ └── tsconfig.json
├── react-native-branch
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── android
│ │ ├── .gitignore
│ │ ├── build.gradle
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── expo
│ │ │ └── modules
│ │ │ └── adapters
│ │ │ └── branch
│ │ │ ├── BranchApplicationLifecycleListener.kt
│ │ │ ├── BranchPackage.kt
│ │ │ └── BranchReactActivityLifecycleListener.kt
│ ├── app.plugin.js
│ ├── expo-module.config.json
│ ├── ios
│ │ ├── ExpoAdapterBranch.podspec
│ │ └── ExpoAdapterBranch
│ │ │ └── BranchAppDelegate.swift
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── fixtures
│ │ │ │ └── react-native-AndroidManifest.xml
│ │ │ ├── withBranchAndroid.test.ts
│ │ │ └── withBranchIOS.test.ts
│ │ ├── types.ts
│ │ ├── withBranch.ts
│ │ ├── withBranchAndroid.ts
│ │ └── withBranchIOS.ts
│ └── tsconfig.json
├── react-native-callkeep
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── ensureHeaderSearchPath.ts
│ │ └── withCallkeep.ts
│ └── tsconfig.json
├── react-native-dynamic-app-icon
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── react-native-pdf
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── withPdf.test.ts.snap
│ │ │ └── withPdf.test.ts
│ │ └── withPdf.ts
│ └── tsconfig.json
├── react-native-quick-actions
│ └── README.md
├── react-native-siri-shortcut
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── __snapshots__
│ │ │ │ └── withReactNativeSiriShortcut.test.ts.snap
│ │ │ └── withReactNativeSiriShortcut.test.ts
│ │ └── withReactNativeSiriShortcut.ts
│ └── tsconfig.json
├── react-native-webrtc
│ ├── .eslintrc.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── app.plugin.js
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── withBitcodeDisabled.ts
│ │ ├── withPermissions.ts
│ │ └── withWebRTC.ts
│ └── tsconfig.json
└── tv
│ └── README.md
├── scripts
├── generate-plugin.ts
├── gh-issues-config.ts
├── template
│ ├── README.md
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
└── update-dependabot-config.ts
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | packages/*/build/** -diff linguist-generated
2 | packages/*/plugin/build/** -diff linguist-generated
3 | packages/@*/*/build/** -diff linguist-generated
4 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | /* @EvanBacon
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: 🐛 Expo Config Plugin Bug Report
2 | description: Report a reproducible bug with one of the Expo Config Plugins.
3 | labels: bug
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: >-
8 | Thanks for taking the time to file a bug report! Please fill out this
9 | form as completely as possible.
10 | - type: markdown
11 | attributes:
12 | value: >-
13 | If you leave out sections there is a high likelihood your issue will be
14 | closed. If you have a question, not a bug report, please post it on our
15 | [forums](https://forums.expo.dev/) instead.
16 | - type: textarea
17 | attributes:
18 | label: Summary
19 | description: Describe the issue in 1 or 2 sentences
20 | placeholder: >-
21 | Clearly describe what the expected behavior is vs. what is actually
22 | happening. This should be as short as possible, while still
23 | communicating all the necessary information. If your summary is just 'X
24 | library/method isn't working', then you need to continue debugging
25 | yourself and provide more information.
26 | validations:
27 | required: true
28 | - type: dropdown
29 | attributes:
30 | label: Config Plugin
31 | options:
32 | - '@config-plugins/android-jsc-intl'
33 | - '@config-plugins/apple-settings'
34 | - '@config-plugins/detox'
35 | - '@config-plugins/ffmpeg-kit-react-native'
36 | - '@config-plugins/ios-stickers'
37 | - '@config-plugins/react-native-adjust'
38 | - '@config-plugins/react-native-blob-util'
39 | - '@config-plugins/react-native-branch'
40 | - '@config-plugins/react-native-callkeep'
41 | - '@config-plugins/react-native-dynamic-app-icon'
42 | - '@config-plugins/react-native-pdf'
43 | - '@config-plugins/react-native-siri-shortcut'
44 | - '@config-plugins/react-native-webrtc'
45 | validations:
46 | required: true
47 | - type: dropdown
48 | attributes:
49 | label: What platform(s) does this occur on?
50 | multiple: true
51 | options:
52 | - Android
53 | - iOS
54 | validations:
55 | required: true
56 | - type: input
57 | attributes:
58 | label: SDK Version
59 | description: What version of the Expo SDK are you using?
60 | - type: textarea
61 | attributes:
62 | label: Reproducible demo
63 | description: >-
64 | This should include as little code as possible, do not simply link your
65 | entire project. If a reproducible demo is not provided, it is very
66 | likely your issue will be closed. Read [here more
67 | guidance](https://stackoverflow.com/help/mcve).
68 | validations:
69 | required: true
70 | - type: markdown
71 | attributes:
72 | value: >-
73 | Please make sure contributors can run your code and follow the steps
74 | your provided in order to reproduce the bug.
75 | - type: markdown
76 | attributes:
77 | value: >-
78 | **Realize that it is up to you to debug your code and be as certain as
79 | possible that the bug is with Expo, not with your own app.** [Here's an
80 | excellent guide to debugging you can
81 | follow](https://gist.github.com/brentvatne/5ac00cba0c70b7a06b89a56787d6bc4a).
82 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | blank_issues_enabled: false
3 | contact_links:
4 | - name: 🤔 Question about an Expo Config Plugin
5 | about: >-
6 | If you have a question about an Expo Config Plugin, please ask it on the
7 | forums, discord, Twitter, or Stack Overflow.
8 | url: https://forums.expo.io/
9 | - about: E2E tests and automation for mobile
10 | name: 📦 detox issues
11 | url: https://github.com/wix/Detox/issues
12 | - about: FFmpeg Kit for React Native
13 | name: 📦 ffmpeg-kit-react-native issues
14 | url: https://github.com/arthenica/ffmpeg-kit/issues
15 | - about: Adjust React Native SDK
16 | name: 📦 react-native-adjust issues
17 | url: https://github.com/adjust/react_native_sdk/issues
18 | - about: >-
19 | A module provides upload, download, and files access API. Supports file
20 | stream read/write for process large files.
21 | name: 📦 react-native-blob-util issues
22 | url: https://github.com/RonRadtke/react-native-blob-util/issues
23 | - about: iOS 10 CallKit and Android ConnectionService Framework For React Native
24 | name: 📦 react-native-callkeep issues
25 | url: https://github.com/react-native-webrtc/react-native-callkeep/issues
26 | - about: Programmatically change the app icon in React Native.
27 | name: 📦 react-native-dynamic-app-icon issues
28 | url: https://github.com/idearockers/react-native-dynamic-app-icon/issues
29 | - about: A react native PDF view component, support ios and android platform
30 | name: 📦 react-native-pdf issues
31 | url: https://github.com/wonday/react-native-pdf/issues
32 | - about: A React Native library that enables you to use iOS 12+ Siri Shortcuts.
33 | name: 📦 react-native-siri-shortcut issues
34 | url: https://github.com/Gustash/react-native-siri-shortcut/issues
35 | - about: WebRTC for React Native
36 | name: 📦 react-native-webrtc issues
37 | url: https://github.com/react-native-webrtc/react-native-webrtc/issues
38 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement.yml:
--------------------------------------------------------------------------------
1 | name: "⭐️ Config Plugin Request"
2 | description: "Suggest an idea for a new Expo Config Plugin."
3 | labels: enhancement
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: "This repo is used for publishing out-of-tree plugins that should eventually be upstreamed in a particular package. If the plugin is a utility or used to improve some particular workflow i.e. updates version numbers, than it's probably better suited for a personal repo or utility package."
8 | - type: input
9 | attributes:
10 | label: Library
11 | description: What package does this Config Plugin configure.
12 | placeholder: URL to a React Native package.
13 | validations:
14 | required: true
15 | - type: textarea
16 | attributes:
17 | label: Summary
18 | description: Add some info on why this integration is important.
19 | - type: textarea
20 | attributes:
21 | label: Any existing examples?
22 | placeholder: Have you already created a local plugin for the requested library?
23 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE:
--------------------------------------------------------------------------------
1 |
7 |
8 | # Why
9 |
10 |
13 |
14 | # How
15 |
16 |
19 |
20 | # Test Plan
21 |
22 |
25 |
--------------------------------------------------------------------------------
/.github/workflows/lint-md.yml:
--------------------------------------------------------------------------------
1 | name: Check Markdown links
2 | on:
3 | workflow_dispatch: {}
4 | push:
5 | branches: [main]
6 | paths:
7 | - .github/workflows/lint-md.yml
8 | - "**.md"
9 | pull_request:
10 | paths:
11 | - .github/workflows/lint-md.yml
12 | - "**.md"
13 |
14 | jobs:
15 | lint-md:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v2
19 | - run: yarn install --frozen-lockfile --check-files
20 | - run: npx remark --use validate-links . .github
21 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test Packages
2 | on:
3 | push:
4 | branches: [main]
5 | pull_request:
6 | types: [opened, synchronize]
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | strategy:
12 | matrix:
13 | node: ["18"]
14 | name: Build with Node ${{ matrix.node }}
15 | steps:
16 | - uses: actions/checkout@v2
17 | with:
18 | fetch-depth: 1
19 | - name: Setup node
20 | uses: actions/setup-node@v1
21 | with:
22 | node-version: ${{ matrix.node }}
23 | - run: yarn install --frozen-lockfile --check-files
24 | - run: yarn lerna run prepare --stream
25 | - uses: actions/cache@v4
26 | with:
27 | path: "*"
28 | key: v2-${{ github.sha }}-${{ matrix.node }}
29 | test:
30 | runs-on: ubuntu-latest
31 | needs: build
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | node: ["18"]
36 | package: [
37 | # Manually add packages here
38 | ios-stickers,
39 | react-native-blob-util,
40 | react-native-branch,
41 | react-native-siri-shortcut,
42 | react-native-pdf,
43 | ]
44 | name: Test ${{ matrix.package }} on Node ${{ matrix.node }}
45 | steps:
46 | - uses: actions/cache@v4
47 | with:
48 | path: "*"
49 | key: v2-${{ github.sha }}-${{ matrix.node }}
50 | - name: Set up Node
51 | uses: actions/setup-node@v1
52 | with:
53 | node-version: ${{ matrix.node }}
54 | - name: Lint ${{ matrix.package }}
55 | run: yarn lint --max-warnings 0
56 | working-directory: packages/${{ matrix.package }}
57 | - name: Test ${{ matrix.package }}
58 | run: yarn test
59 | working-directory: packages/${{ matrix.package }}
60 | env:
61 | CI: true
62 | EXPO_DEBUG: true
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Expo
2 | .expo
3 | __generated__
4 | web-build
5 |
6 | # macOS
7 | .DS_Store
8 |
9 | # Node
10 | node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # Ruby
15 | .direnv
16 |
17 | # Emacs
18 | *~
19 |
20 | # Vim
21 | .*.swp
22 | .*.swo
23 | .*.swn
24 | .*.swm
25 |
26 | # Sublime Text
27 | *.sublime-project
28 | *.sublime-workspace
29 |
30 | # Xcode
31 | *.pbxuser
32 | !default.pbxuser
33 | *.xccheckout
34 | *.xcscmblueprint
35 | xcuserdata
36 |
37 | # Android Studio
38 | *.iml
39 | .gradle
40 | .idea/libraries
41 | .idea/workspace.xml
42 | .idea/gradle.xml
43 | .idea/misc.xml
44 | .idea/modules.xml
45 | .idea/vcs.xml
46 |
47 | # Eclipse
48 | .project
49 | .settings
50 |
51 | # VSCode
52 | .history/
53 |
54 | # Ignore build folders
55 |
56 | packages/*/build/**
57 | packages/*/plugin/build/**
58 | packages/@*/*/build/**
59 |
60 |
61 | # App native folders
62 |
63 | apps/*/ios/*
64 | apps/*/android/*
65 | apps/*/web-build/*
66 | apps/*/dist/*
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Expo Config Plugins
2 |
3 | ## Submitting a pull request
4 |
5 | To submit a pull request:
6 |
7 | 1. Fork the [repository](https://github.com/expo/config-plugins) and create a feature branch. (Existing contributors can create feature branches without forking. Prefix the branch name with `@your-github-username/`.)
8 | 2. Run `yarn` in the root directory to generate the build files.
9 | 3. Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) including in the PR title.
10 | 4. Fill out the entire PR template. Ensure your code is tested locally and has continuous tests in CI.
11 | 5. Make sure all tests pass on GitHub Actions.
12 | 6. Wait for a review and adjust the code if necessary.
13 |
14 | ## Creating a plugin
15 |
16 | - Plugins can be generated by running `yarn gen`.
17 | - Add plugins to the example in [`apps/app`](/apps/app/package.json) to test them.
18 | - The example app should always stay in a state of regeneration.
19 |
20 | Be sure to run the following scripts in the **root directory** to update automation tools:
21 |
22 | - Update dependabot: `yarn update-dependabot-config`
23 | - Update the issue template: `yarn update-issue-template`
24 |
25 | ## Publishing a release
26 |
27 | All publishing should be handled automatically whenever code is merged to `main`.
28 |
--------------------------------------------------------------------------------
/apps/app/.gitignore:
--------------------------------------------------------------------------------
1 | /scripts/start.command
2 | /artifacts
--------------------------------------------------------------------------------
/apps/app/App.tsx:
--------------------------------------------------------------------------------
1 | export { default } from "./src/android-jsc-intl/App";
2 | // export { default } from "./src/react-native-adjust/App";
3 |
--------------------------------------------------------------------------------
/apps/app/app.config.js:
--------------------------------------------------------------------------------
1 | module.exports = ({ config }) => {
2 | if (!config.extra) config.extra = {};
3 | // Expose CI env variables to the app
4 | config.extra.CI = process.env.CI;
5 | return config;
6 | };
7 |
--------------------------------------------------------------------------------
/apps/app/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "app",
4 | "slug": "app",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "https://github.com/expo.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": ["**/*"],
17 | "ios": {
18 | "supportsTablet": true,
19 | "bundleIdentifier": "dev.bacon.app"
20 | },
21 | "android": {
22 | "adaptiveIcon": {
23 | "foregroundImage": "./assets/adaptive-icon.png",
24 | "backgroundColor": "#FFFFFF"
25 | },
26 | "package": "com.bacon.app"
27 | },
28 | "web": {
29 | "favicon": "./assets/favicon.png"
30 | },
31 | "plugins": [
32 | "@config-plugins/react-native-adjust",
33 | "@config-plugins/react-native-callkeep",
34 | "@config-plugins/android-jsc-intl",
35 | "expo-localization"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/apps/app/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/apps/app/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/assets/favicon.png
--------------------------------------------------------------------------------
/apps/app/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/assets/icon.png
--------------------------------------------------------------------------------
/apps/app/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/assets/splash.png
--------------------------------------------------------------------------------
/apps/app/meta/screenshots/android/en-US/APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/meta/screenshots/android/en-US/APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png
--------------------------------------------------------------------------------
/apps/app/meta/screenshots/android/nl-NL/APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/meta/screenshots/android/nl-NL/APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png
--------------------------------------------------------------------------------
/apps/app/meta/screenshots/android/zh-CN/APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/app/meta/screenshots/android/zh-CN/APP_EMULATOR-5554 (PIXEL_6_PRO_API_33)_0.png
--------------------------------------------------------------------------------
/apps/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@expo/app",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "private": true,
6 | "scripts": {
7 | "start": "expo start --dev-client",
8 | "ios": "expo run:ios",
9 | "android": "expo run:android"
10 | },
11 | "dependencies": {
12 | "@config-plugins/android-jsc-intl": "*",
13 | "@config-plugins/react-native-adjust": "*",
14 | "@config-plugins/react-native-callkeep": "*",
15 | "expo": "~53",
16 | "expo-localization": "~16.1.5",
17 | "expo-splash-screen": "~0.30.7",
18 | "fbjs": "^0.8.18",
19 | "i18n-js": "^3.8.0",
20 | "luxon": "^1.27.0",
21 | "react": "19.0.0",
22 | "react-native": "0.79.2",
23 | "react-native-adjust": "^5.1.0",
24 | "react-native-callkeep": "^4.3.16",
25 | "react-native-safe-area-context": "5.3.0"
26 | },
27 | "devDependencies": {
28 | "@babel/plugin-syntax-jsx": "^7.16.0",
29 | "@types/jest": "^29.4.0",
30 | "@types/luxon": "^1.27.1",
31 | "babel-jest": "^29.5.0",
32 | "jest": "~29.7.0",
33 | "jest-circus": "^29.5.0",
34 | "ts-jest": "^29.0.5",
35 | "typescript": "~5.8.3"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/apps/app/scripts/build-detox-ios.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # This script wraps the xcodebuild command and exits with non-zero if the build fails.
4 | #
5 | # This ensures that CI fails on the correct step instead of attempting to run Detox tests without a
6 | # build.
7 |
8 | set -eu
9 |
10 | iosName=$1
11 | # Debug or Release
12 | configuration=${3:-"Debug"}
13 | # YES or NO
14 | UseModernBuildSystem=${3:-"NO"}
15 |
16 | xcodebuild \
17 | -workspace ios/$iosName.xcworkspace \
18 | -scheme $iosName \
19 | -configuration "$configuration" \
20 | -sdk iphonesimulator \
21 | -derivedDataPath "ios/build" \
22 | -UseModernBuildSystem="$UseModernBuildSystem" 2>&1 | npx excpretty ./
23 |
24 | if [ "${PIPESTATUS[0]}" -ne "0" ]; then
25 | echo 'Build Failed'
26 | set +e
27 | exit 1
28 | fi
29 |
30 | echo 'Build Succeeded'
31 |
--------------------------------------------------------------------------------
/apps/app/scripts/start-metro.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | port=${1:-8081}
4 |
5 | PACKAGER_STATUS_URL="http://localhost:${port}/status"
6 | # Check if Metro is running
7 | STATUS=$(curl --silent $PACKAGER_STATUS_URL)
8 |
9 | if [ "${STATUS}" = "packager-status:running" ]; then
10 | echo " ✅ Verified Metro Bundler is running."
11 | else
12 | echo " ⚠️ Starting Metro Bundler..."
13 | # yarn run clear-metro
14 | # yarn start
15 |
16 | commandFile=$(dirname "$0")/start.command
17 | cat > ${commandFile} << EOF
18 | cd "\$(dirname "\$0")/.."
19 | # Run 'npx expo start --help' to get more parameters
20 | yarn start --port ${port}
21 | EOF
22 | # execute the file in a new command line window
23 | chmod 0755 ${commandFile}
24 | case "$OSTYPE" in
25 | darwin*)
26 | open ${commandFile}
27 | ;;
28 | *)
29 | # Spawns a new terminal window and detaches it
30 | # Assuming the non-standard variable $TERMINAL is set
31 | if [ -z "$TERMINAL" ]; then
32 | echo "Could not open a new terminal window. Please make sure to export TERMINAL='your-terminal'"
33 | else
34 | nohup "$TERMINAL" -e "${commandFile}" /dev/null 2>&1 &
35 | fi
36 | ;;
37 | esac
38 |
39 | fi
--------------------------------------------------------------------------------
/apps/app/src/android-jsc-intl/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Text, View } from "react-native";
3 | import { DateTime } from "luxon";
4 |
5 | const currentDate = DateTime.fromObject({
6 | locale: "en-US",
7 | zone: "America/New_York",
8 | });
9 |
10 | export default function App() {
11 | return (
12 |
20 |
21 | Intl support for Android, without Hermes 🤖
22 |
23 |
24 | {currentDate.toISO()}
25 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/apps/app/src/react-native-adjust/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { SafeAreaView, Text, StyleSheet } from "react-native";
3 | import { Adjust, AdjustConfig } from "react-native-adjust";
4 |
5 | export default function App() {
6 | React.useEffect(() => {
7 | const adjustConfig = new AdjustConfig(
8 | "APP_TOKEN",
9 | AdjustConfig.EnvironmentSandbox
10 | );
11 | Adjust.enable();
12 | }, []);
13 |
14 | return (
15 |
16 | Adjust SDK
17 |
18 | );
19 | }
20 |
21 | const styles = StyleSheet.create({
22 | container: {
23 | flex: 1,
24 | justifyContent: "center",
25 | alignItems: "center",
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/apps/app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {},
3 | "extends": "expo/tsconfig.base"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/apple-settings/app.config.ts:
--------------------------------------------------------------------------------
1 | import withAppleSettings, {
2 | ChildPane,
3 | Group,
4 | RadioGroup,
5 | Slider,
6 | Switch,
7 | TextField,
8 | Title,
9 | } from "@config-plugins/apple-settings";
10 | import { MultiValue } from "@config-plugins/apple-settings/build/models";
11 | import { ConfigContext, ExpoConfig } from "expo/config";
12 | import path from "node:path";
13 |
14 | const folderName = path.basename(__dirname);
15 | const cleanName = folderName.replace(/[_\s-]/g, "");
16 | const appId = "dev.bacon." + cleanName;
17 |
18 | function withWhiteLabel(config: Partial) {
19 | if (!config.extra) config.extra = {};
20 | // Expose CI env variables to the app
21 | config.extra.CI = process.env.CI;
22 |
23 | if (!config.ios) config.ios = {};
24 | config.ios.bundleIdentifier = appId;
25 | if (!config.android) config.android = {};
26 | config.android.package = appId;
27 |
28 | return config;
29 | }
30 |
31 | module.exports = ({ config }: ConfigContext): Partial => {
32 | config = withWhiteLabel(config);
33 |
34 | config = withAppleSettings(config as ExpoConfig, {
35 | // The name of the .plist file to generate. Root is the default and must be provided.
36 | Root: {
37 | // The locales object is optional. If provided, it will be used to generate the localized .strings files.
38 | locales: {
39 | // The Apple locale code. This will be used to generate the .strings file.
40 | en: {
41 | // Name of the localized key.
42 | Name: "Text Field",
43 | },
44 | },
45 | // The page object is required. It will be used to generate the .plist file.
46 | // The contents will be converted directly to plist.
47 | page: {
48 | // The `PreferenceSpecifiers` defines the UI elements to generate.
49 | PreferenceSpecifiers: [
50 | Title({
51 | title: "Title",
52 | value: "Default Title",
53 | key: "title_preference",
54 | }),
55 | // Helper models can be used to generate the UI elements using
56 | // an API that's similar to React Native.
57 | TextField({
58 | title: "Name",
59 | key: "name_preference",
60 | value: "",
61 | keyboardType: "Alphabet",
62 | autoCapitalize: "None",
63 | autoCorrect: "No",
64 | }),
65 | Switch({
66 | title: "Enabled",
67 | key: "enabled_preference",
68 | value: true,
69 | }),
70 | Slider({
71 | key: "slider_preference",
72 | value: 0.5,
73 | }),
74 | // Broken https://forums.developer.apple.com/forums/thread/764519
75 | // RadioGroup({
76 | // value: "option1",
77 | // key: "radio_preference",
78 | // items: [
79 | // {
80 | // title: "Option 1",
81 | // value: "option1",
82 | // },
83 |
84 | // {
85 | // title: "Option 2",
86 | // value: "option2",
87 | // },
88 | // ],
89 | // }),
90 | // MultiValue({
91 | // title: "Multi Value",
92 | // key: "multi_value_preference",
93 | // value: "alpha",
94 | // items: [
95 | // {
96 | // title: "Alpha",
97 | // value: "alpha",
98 | // short: "α",
99 | // },
100 | // {
101 | // title: "Beta",
102 | // value: "beta",
103 | // short: "β",
104 | // },
105 | // {
106 | // title: "Delta",
107 | // value: "delta",
108 | // short: "Δ",
109 | // },
110 | // {
111 | // title: "Omega",
112 | // value: "omega",
113 | // short: "Ω",
114 | // },
115 | // ],
116 | // }),
117 | ],
118 | },
119 | },
120 | });
121 |
122 | return config;
123 | };
124 |
--------------------------------------------------------------------------------
/apps/apple-settings/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "apple-settings",
4 | "icon": "https://github.com/expo.png",
5 | "platforms": ["ios"],
6 | "plugins": [["expo-build-properties", { "ios": { "ccacheEnabled": true } }]]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/apps/apple-settings/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/apple-settings/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/apple-settings",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "ios": "expo run:ios",
8 | "android": "expo run:android"
9 | },
10 | "dependencies": {
11 | "@config-plugins/apple-settings": "*",
12 | "@react-native-community/slider": "4.5.6",
13 | "@react-native-picker/picker": "2.11.0",
14 | "expo": "~53",
15 | "expo-splash-screen": "~0.30.7",
16 | "react": "19.0.0",
17 | "react-native": "0.79.2"
18 | },
19 | "private": true
20 | }
21 |
--------------------------------------------------------------------------------
/apps/apple-settings/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button, Linking, StyleSheet, View } from "react-native";
3 |
4 | import {
5 | SettingsRadioGroup,
6 | SettingsSlider,
7 | SettingsSwitch,
8 | SettingsTextInput,
9 | SettingsTitle,
10 | } from "./SettingsViews";
11 |
12 | const App = () => {
13 | return (
14 |
15 | {/* */}
16 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
40 | );
41 | };
42 |
43 | const styles = StyleSheet.create({
44 | container: {
45 | flex: 1,
46 | justifyContent: "center",
47 | alignItems: "stretch",
48 | paddingHorizontal: 56,
49 | gap: 12,
50 | },
51 | value: {
52 | fontSize: 24,
53 | marginVertical: 12,
54 | },
55 | });
56 |
57 | export default App;
58 |
--------------------------------------------------------------------------------
/apps/apple-settings/src/SettingsViews.tsx:
--------------------------------------------------------------------------------
1 | import Slider from "@react-native-community/slider";
2 | import { Picker } from "@react-native-picker/picker";
3 | import React from "react";
4 | import { Settings, Switch, Text, TextInput } from "react-native";
5 |
6 | export function useSetting(key: string): [T, (value: T) => void] {
7 | const [value, setValue] = React.useState(() => Settings.get(key));
8 | React.useEffect(() => {
9 | let isMounted = true;
10 | const callback = Settings.watchKeys(key, () => {
11 | if (isMounted) {
12 | setValue(Settings.get(key));
13 | }
14 | });
15 | return () => {
16 | Settings.clearWatch(callback);
17 | isMounted = false;
18 | };
19 | }, [key]);
20 |
21 | return [
22 | value,
23 | (value) => {
24 | Settings.set({ [key]: value });
25 | setValue(value);
26 | },
27 | ];
28 | }
29 |
30 | export function SettingsSlider({
31 | settingsKey,
32 | ...props
33 | }: { settingsKey: string } & Omit<
34 | React.ComponentProps,
35 | "selectedValue" | "onValueChange"
36 | >) {
37 | const [value, setValue] = useSetting(settingsKey);
38 | return ;
39 | }
40 |
41 | export function SettingsRadioGroup({
42 | settingsKey,
43 | ...props
44 | }: { settingsKey: string } & Omit<
45 | React.ComponentProps,
46 | "selectedValue" | "onValueChange"
47 | >) {
48 | const [value, setValue] = useSetting(settingsKey);
49 | return (
50 |
55 | );
56 | }
57 |
58 | SettingsRadioGroup.Item = Picker.Item;
59 |
60 | export function SettingsSwitch({
61 | settingsKey,
62 | ...props
63 | }: { settingsKey: string } & Omit<
64 | React.ComponentProps,
65 | "value" | "onValueChange"
66 | >) {
67 | const [value, setValue] = useSetting(settingsKey);
68 | return ;
69 | }
70 |
71 | export function SettingsTitle({
72 | settingsKey,
73 | ...props
74 | }: { settingsKey: string } & Omit<
75 | React.ComponentProps,
76 | "children"
77 | >) {
78 | const [value] = useSetting(settingsKey);
79 | return ;
80 | }
81 |
82 | export function SettingsTextInput({
83 | settingsKey,
84 | ...props
85 | }: { settingsKey: string } & Omit<
86 | React.ComponentProps,
87 | "value" | "onChangeText"
88 | >) {
89 | const [value, setValue] = useSetting(settingsKey);
90 | return ;
91 | }
92 |
--------------------------------------------------------------------------------
/apps/apple-settings/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {},
3 | "extends": "expo/tsconfig.base"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/ios-stickers/app.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const folderName = path.basename(__dirname);
3 | const cleanName = folderName.replace(/[_\s-]/g, "");
4 | const appId = "dev.bacon." + cleanName;
5 |
6 | module.exports = ({ config }) => {
7 | if (!config.extra) config.extra = {};
8 | // Expose CI env variables to the app
9 | config.extra.CI = process.env.CI;
10 |
11 | if (!config.ios) config.ios = {};
12 | config.ios.bundleIdentifier = appId;
13 | if (!config.android) config.android = {};
14 | config.android.package = appId;
15 | return config;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/ios-stickers/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "stickers",
4 | "icon": "https://github.com/expo.png",
5 | "platforms": ["ios"],
6 | "plugins": [
7 | [
8 | "@config-plugins/ios-stickers",
9 | {
10 | "name": "Stickers",
11 | "stickerBundleId": "dev.bacon.iosstickers.stickers",
12 | "icon": "./assets/imessage-icon.png",
13 | "columns": 4,
14 | "stickers": [
15 | "./assets/stickers/annoyed.png",
16 | "./assets/stickers/cuddle.png",
17 | "./assets/stickers/crazy.png",
18 | "./assets/stickers/cant.png",
19 | "./assets/stickers/donno.png",
20 | "./assets/stickers/cozzy.png",
21 | "./assets/stickers/dork.png",
22 | "./assets/stickers/focus.png",
23 | "./assets/stickers/avocool.png",
24 | "./assets/stickers/coder-girl.png",
25 | "./assets/stickers/teapot.png"
26 | ]
27 | }
28 | ],
29 | ["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
30 | ]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/imessage-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/imessage-icon.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/annoyed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/annoyed.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/avocool.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/avocool.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/cant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/cant.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/coder-girl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/coder-girl.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/cozzy copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/cozzy copy.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/cozzy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/cozzy.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/crazy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/crazy.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/cuddle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/cuddle.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/donno.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/donno.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/dork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/dork.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/focus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/focus.png
--------------------------------------------------------------------------------
/apps/ios-stickers/assets/stickers/teapot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/assets/stickers/teapot.png
--------------------------------------------------------------------------------
/apps/ios-stickers/expo-template-bare-minimum-50.0.17.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/ios-stickers/expo-template-bare-minimum-50.0.17.tgz
--------------------------------------------------------------------------------
/apps/ios-stickers/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/ios-stickers/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/ios-stickers",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "prebuild": "expo prebuild -p ios --template ./expo-template-bare-minimum-50.0.17.tgz",
8 | "ios": "expo run:ios",
9 | "android": "expo run:android"
10 | },
11 | "dependencies": {
12 | "@config-plugins/ios-stickers": "*",
13 | "expo": "~53",
14 | "expo-splash-screen": "~0.30.7",
15 | "react": "19.0.0",
16 | "react-native": "0.79.2"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/apps/ios-stickers/src/App.js:
--------------------------------------------------------------------------------
1 | import { Text, View } from "react-native";
2 |
3 | export default function App() {
4 | return (
5 |
6 | Open iMessage to find the app
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/apps/react-native-branch/app.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const folderName = path.basename(__dirname);
3 | const cleanName = folderName.replace(/[_\s-]/g, "");
4 | const appId = "dev.bacon." + cleanName;
5 |
6 | module.exports = ({ config }) => {
7 | if (!config.extra) config.extra = {};
8 | // Expose CI env variables to the app
9 | config.extra.CI = process.env.CI;
10 |
11 | if (!config.ios) config.ios = {};
12 | config.ios.bundleIdentifier = appId;
13 | if (!config.android) config.android = {};
14 | config.android.package = appId;
15 | return config;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/react-native-branch/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "branch",
4 | "icon": "https://github.com/expo.png",
5 | "splash": {
6 | "image": "https://github.com/expo.png"
7 | },
8 | "ios": {
9 | "config": {
10 | "branch": {
11 | "apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8"
12 | }
13 | }
14 | },
15 | "android": {
16 | "config": {
17 | "branch": {
18 | "apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8"
19 | }
20 | }
21 | },
22 | "plugins": [
23 | "@config-plugins/react-native-branch",
24 | ["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
25 | ]
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/apps/react-native-branch/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/react-native-branch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/react-native-branch",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "ios": "expo run:ios",
8 | "android": "expo run:android"
9 | },
10 | "dependencies": {
11 | "@config-plugins/react-native-branch": "*",
12 | "expo": "~53",
13 | "expo-splash-screen": "~0.30.7",
14 | "react": "19.0.0",
15 | "react-native": "0.79.2",
16 | "react-native-branch": "^6.6.0"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/apps/react-native-branch/src/App.js:
--------------------------------------------------------------------------------
1 | import { Text, View } from "react-native";
2 |
3 | export default function App() {
4 | return (
5 |
6 | Branch
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/app.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const folderName = path.basename(__dirname);
3 | const cleanName = folderName.replace(/[_\s-]/g, "");
4 | const appId = "dev.bacon." + cleanName;
5 |
6 | module.exports = ({ config }) => {
7 | if (!config.extra) config.extra = {};
8 | // Expose CI env variables to the app
9 | config.extra.CI = process.env.CI;
10 |
11 | if (!config.ios) config.ios = {};
12 | config.ios.bundleIdentifier = appId;
13 | if (!config.android) config.android = {};
14 | config.android.package = appId;
15 | return config;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "app-icon",
4 | "icon": "./assets/icons/winter.png",
5 | "platforms": ["ios"],
6 | "ios": {
7 | "supportsTablet": true
8 | },
9 | "plugins": [
10 | [
11 | "@config-plugins/react-native-dynamic-app-icon",
12 | [
13 | "./assets/icons/spring.png",
14 | "./assets/icons/summer.png",
15 | "./assets/icons/autumn.png",
16 | "./assets/icons/fall.png",
17 | "./assets/icons/solstice.png"
18 | ]
19 | ],
20 | ["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
21 | ]
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/assets/icons/autumn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/react-native-dynamic-app-icon/assets/icons/autumn.png
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/assets/icons/fall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/react-native-dynamic-app-icon/assets/icons/fall.png
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/assets/icons/solstice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/react-native-dynamic-app-icon/assets/icons/solstice.png
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/assets/icons/spring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/react-native-dynamic-app-icon/assets/icons/spring.png
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/assets/icons/summer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/react-native-dynamic-app-icon/assets/icons/summer.png
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/assets/icons/winter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/apps/react-native-dynamic-app-icon/assets/icons/winter.png
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/react-native-dynamic-app-icon",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "ios": "expo run:ios",
8 | "android": "expo run:android"
9 | },
10 | "dependencies": {
11 | "@config-plugins/react-native-dynamic-app-icon": "*",
12 | "expo": "~53",
13 | "expo-splash-screen": "~0.30.7",
14 | "react": "19.0.0",
15 | "react-native": "0.79.2",
16 | "react-native-dynamic-app-icon": "^1.1.0"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/apps/react-native-dynamic-app-icon/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {},
3 | "extends": "expo/tsconfig.base"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/react-native-pdf/app.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const folderName = path.basename(__dirname);
3 | const cleanName = folderName.replace(/[_\s-]/g, "");
4 | const appId = "dev.bacon." + cleanName;
5 |
6 | module.exports = ({ config }) => {
7 | if (!config.extra) config.extra = {};
8 | // Expose CI env variables to the app
9 | config.extra.CI = process.env.CI;
10 |
11 | if (!config.ios) config.ios = {};
12 | config.ios.bundleIdentifier = appId;
13 | if (!config.android) config.android = {};
14 | config.android.package = appId;
15 | return config;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/react-native-pdf/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "pdf",
4 | "icon": "https://github.com/expo.png",
5 | "splash": {
6 | "image": "https://github.com/expo.png"
7 | },
8 | "plugins": [
9 | "@config-plugins/react-native-blob-util",
10 | "@config-plugins/react-native-pdf",
11 | ["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/apps/react-native-pdf/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/react-native-pdf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/react-native-pdf",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "ios": "expo run:ios",
8 | "android": "expo run:android"
9 | },
10 | "dependencies": {
11 | "@config-plugins/react-native-blob-util": "*",
12 | "@config-plugins/react-native-pdf": "*",
13 | "expo": "~53",
14 | "expo-splash-screen": "~0.30.7",
15 | "react": "19.0.0",
16 | "react-native": "0.79.2",
17 | "react-native-blob-util": "^0.21.2",
18 | "react-native-pdf": "^6.7.7"
19 | },
20 | "private": true
21 | }
22 |
--------------------------------------------------------------------------------
/apps/react-native-pdf/src/App.js:
--------------------------------------------------------------------------------
1 | import { SafeAreaView, StyleSheet, useWindowDimensions } from "react-native";
2 | import Pdf from "react-native-pdf";
3 |
4 | const source = {
5 | uri: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
6 | cache: true,
7 | };
8 | export default function App() {
9 | const { width, height } = useWindowDimensions();
10 |
11 | return (
12 |
13 | {
17 | console.log(`Number of pages: ${numberOfPages}`);
18 | }}
19 | onPageChanged={(page, numberOfPages) => {
20 | console.log(`Current page: ${page}`);
21 | }}
22 | onError={(error) => {
23 | console.log(error);
24 | }}
25 | onPressLink={(uri) => {
26 | console.log(`Link pressed: ${uri}`);
27 | }}
28 | style={{ flex: 1, width, height }}
29 | />
30 |
31 | );
32 | }
33 |
34 | const styles = StyleSheet.create({
35 | container: {
36 | flex: 1,
37 | justifyContent: "flex-start",
38 | alignItems: "center",
39 | },
40 | });
41 |
--------------------------------------------------------------------------------
/apps/react-native-siri-shortcut/app.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const folderName = path.basename(__dirname);
3 | const cleanName = folderName.replace(/[_\s-]/g, "");
4 | const appId = "dev.bacon." + cleanName;
5 |
6 | module.exports = ({ config }) => {
7 | if (!config.extra) config.extra = {};
8 | // Expose CI env variables to the app
9 | config.extra.CI = process.env.CI;
10 |
11 | if (!config.ios) config.ios = {};
12 | config.ios.bundleIdentifier = appId;
13 | if (!config.android) config.android = {};
14 | config.android.package = appId;
15 | return config;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/react-native-siri-shortcut/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "siri xcut",
4 | "icon": "https://github.com/expo.png",
5 | "platforms": ["ios"],
6 | "splash": {
7 | "image": "https://github.com/expo.png"
8 | },
9 | "plugins": [
10 | [
11 | "@config-plugins/react-native-siri-shortcut",
12 | ["com.example.InitiateWorkout", "com.example.FinishWorkout"]
13 | ],
14 | ["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
15 | ]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/apps/react-native-siri-shortcut/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/react-native-siri-shortcut/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/react-native-siri-shortcut",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "ios": "expo run:ios",
8 | "android": "expo run:android"
9 | },
10 | "dependencies": {
11 | "@config-plugins/react-native-siri-shortcut": "*",
12 | "expo": "~53",
13 | "expo-splash-screen": "~0.30.7",
14 | "react": "19.0.0",
15 | "react-native": "0.79.2",
16 | "react-native-siri-shortcut": "^3.2.4"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/apps/react-native-siri-shortcut/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { View, Text } from "react-native";
2 |
3 | export default function App() {
4 | return (
5 |
6 | No-op on this platform
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/apps/react-native-siri-shortcut/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {},
3 | "extends": "expo/tsconfig.base"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/react-native-webrtc/app.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const folderName = path.basename(__dirname);
3 | const cleanName = folderName.replace(/[_\s-]/g, "");
4 | const appId = "dev.bacon." + cleanName;
5 |
6 | module.exports = ({ config }) => {
7 | if (!config.extra) config.extra = {};
8 | // Expose CI env variables to the app
9 | config.extra.CI = process.env.CI;
10 |
11 | if (!config.ios) config.ios = {};
12 | config.ios.bundleIdentifier = appId;
13 | if (!config.android) config.android = {};
14 | config.android.package = appId;
15 | return config;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/react-native-webrtc/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "webrtc",
4 | "icon": "https://github.com/expo.png",
5 | "splash": {
6 | "image": "https://github.com/expo.png"
7 | },
8 | "plugins": [
9 | "@config-plugins/react-native-webrtc",
10 | ["expo-build-properties", { "ios": { "ccacheEnabled": true } }]
11 | ]
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/apps/react-native-webrtc/index.js:
--------------------------------------------------------------------------------
1 | import { registerRootComponent } from "expo";
2 |
3 | import App from "./src/App";
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/apps/react-native-webrtc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins-app/react-native-webrtc",
3 | "main": "./index.js",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start --dev-client",
7 | "ios": "expo run:ios",
8 | "android": "expo run:android"
9 | },
10 | "dependencies": {
11 | "@config-plugins/react-native-webrtc": "*",
12 | "expo": "~53",
13 | "expo-splash-screen": "~0.30.7",
14 | "react": "19.0.0",
15 | "react-native": "0.79.2",
16 | "react-native-webrtc": "^124.0.5"
17 | },
18 | "private": true
19 | }
20 |
--------------------------------------------------------------------------------
/apps/react-native-webrtc/src/App.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import {
3 | Button,
4 | SafeAreaView,
5 | StatusBar,
6 | StyleSheet,
7 | View,
8 | } from "react-native";
9 | import { mediaDevices, RTCView } from "react-native-webrtc";
10 |
11 | const App = () => {
12 | const [stream, setStream] = useState(null);
13 | const start = async () => {
14 | console.log("start");
15 | if (!stream) {
16 | let s;
17 | try {
18 | s = await mediaDevices.getUserMedia({ video: true });
19 | setStream(s);
20 | } catch (e) {
21 | console.error(e);
22 | }
23 | }
24 | };
25 | const stop = () => {
26 | console.log("stop");
27 | if (stream) {
28 | stream.release();
29 | setStream(null);
30 | }
31 | };
32 | return (
33 | <>
34 |
35 |
36 | {stream && }
37 |
38 |
39 |
40 |
41 |
42 | >
43 | );
44 | };
45 |
46 | const styles = StyleSheet.create({
47 | body: {
48 | ...StyleSheet.absoluteFillObject,
49 | },
50 | stream: {
51 | flex: 1,
52 | },
53 | footer: {
54 | position: "absolute",
55 | bottom: 0,
56 | left: 0,
57 | right: 0,
58 | },
59 | });
60 |
61 | export default App;
62 |
--------------------------------------------------------------------------------
/apps/react-native-webrtc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {},
3 | "extends": "expo/tsconfig.base"
4 | }
5 |
--------------------------------------------------------------------------------
/fixtures/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 | return [self bundleURL];
22 | }
23 |
24 | - (NSURL *)bundleURL
25 | {
26 | #if DEBUG
27 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
28 | #else
29 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
30 | #endif
31 | }
32 |
33 | // Linking API
34 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options {
35 | return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
36 | }
37 |
38 | // Universal Links
39 | - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler {
40 | BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
41 | return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
42 | }
43 |
44 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
45 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
46 | {
47 | return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
48 | }
49 |
50 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
51 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
52 | {
53 | return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
54 | }
55 |
56 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
57 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
58 | {
59 | return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/fixtures/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Expo
2 | import React
3 | import ReactAppDependencyProvider
4 |
5 | @UIApplicationMain
6 | public class AppDelegate: ExpoAppDelegate {
7 | var window: UIWindow?
8 |
9 | var reactNativeDelegate: ExpoReactNativeFactoryDelegate?
10 | var reactNativeFactory: RCTReactNativeFactory?
11 |
12 | public override func application(
13 | _ application: UIApplication,
14 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
15 | ) -> Bool {
16 | let delegate = ReactNativeDelegate()
17 | let factory = ExpoReactNativeFactory(delegate: delegate)
18 | delegate.dependencyProvider = RCTAppDependencyProvider()
19 |
20 | reactNativeDelegate = delegate
21 | reactNativeFactory = factory
22 | bindReactNativeFactory(factory)
23 |
24 | #if os(iOS) || os(tvOS)
25 | window = UIWindow(frame: UIScreen.main.bounds)
26 | factory.startReactNative(
27 | withModuleName: "main",
28 | in: window,
29 | launchOptions: launchOptions)
30 | #endif
31 |
32 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
33 | }
34 |
35 | // Linking API
36 | public override func application(
37 | _ app: UIApplication,
38 | open url: URL,
39 | options: [UIApplication.OpenURLOptionsKey: Any] = [:]
40 | ) -> Bool {
41 | return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)
42 | }
43 |
44 | // Universal Links
45 | public override func application(
46 | _ application: UIApplication,
47 | continue userActivity: NSUserActivity,
48 | restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
49 | ) -> Bool {
50 | let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
51 | return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result
52 | }
53 | }
54 |
55 | class ReactNativeDelegate: ExpoReactNativeFactoryDelegate {
56 | // Extension point for config-plugins
57 |
58 | override func sourceURL(for bridge: RCTBridge) -> URL? {
59 | // needed to return the correct URL for expo-dev-client.
60 | bridge.bundleURL ?? bundleURL()
61 | }
62 |
63 | override func bundleURL() -> URL? {
64 | #if DEBUG
65 | return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry")
66 | #else
67 | return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
68 | #endif
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/fixtures/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'] || '15.1'
11 | install! 'cocoapods',
12 | :deterministic_uuids => false
13 |
14 | prepare_react_native_project!
15 |
16 | target 'HelloWorld' do
17 | use_expo_modules!
18 |
19 | if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
20 | config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
21 | else
22 | config_command = [
23 | 'node',
24 | '--no-warnings',
25 | '--eval',
26 | 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
27 | 'react-native-config',
28 | '--json',
29 | '--platform',
30 | 'ios'
31 | ]
32 | end
33 |
34 | config = use_native_modules!(config_command)
35 |
36 | use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
37 | use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
38 |
39 | use_react_native!(
40 | :path => config[:reactNativePath],
41 | :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
42 | # An absolute path to your application root.
43 | :app_path => "#{Pod::Config.instance.installation_root}/..",
44 | :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
45 | )
46 |
47 | post_install do |installer|
48 | react_native_post_install(
49 | installer,
50 | config[:reactNativePath],
51 | :mac_catalyst_enabled => false,
52 | :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
53 | )
54 |
55 | # This is necessary for Xcode 14, because it signs resource bundles by default
56 | # when building for devices.
57 | installer.target_installation_results.pod_target_installation_results
58 | .each do |pod_name, target_installation_result|
59 | target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
60 | resource_bundle_target.build_configurations.each do |config|
61 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
62 | end
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/fixtures/README.md:
--------------------------------------------------------------------------------
1 | - `AppDelegate`: https://github.com/expo/expo/blob/main/templates/expo-template-bare-minimum/ios/HelloWorld/AppDelegate.mm
2 | - `build.gradle`: https://github.com/expo/expo/blob/main/templates/expo-template-bare-minimum/android/build.gradle
3 | - `app/build.gradle`: https://github.com/expo/expo/blob/main/templates/expo-template-bare-minimum/android/app/build.gradle
4 |
--------------------------------------------------------------------------------
/fixtures/app-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 |
--------------------------------------------------------------------------------
/fixtures/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') ?: '35.0.0'
6 | minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
7 | compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
8 | targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
9 | kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.24'
10 |
11 | ndkVersion = "26.1.10909125"
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 | classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
21 | }
22 | }
23 |
24 | apply plugin: "com.facebook.react.rootproject"
25 |
26 | allprojects {
27 | repositories {
28 | maven {
29 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
30 | url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
31 | }
32 | maven {
33 | // Android JSC is installed from npm
34 | url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
35 | }
36 |
37 | google()
38 | mavenCentral()
39 | maven { url 'https://www.jitpack.io' }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/fixtures/getFixtures.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import fs from "fs";
3 |
4 | export function getFixture(
5 | name:
6 | | "AppDelegate.mm"
7 | | "AppDelegate.swift"
8 | | "app-build.gradle"
9 | | "build.gradle"
10 | | "Podfile"
11 | | "app-Bridging-Header.h"
12 | ): string {
13 | const filepath = path.join(__dirname, name);
14 | return fs.readFileSync(filepath, "utf8");
15 | }
16 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "npmClient": "yarn",
3 | "registry": "https://registry.npmjs.org/",
4 | "useWorkspaces": true,
5 | "version": "independent",
6 | "packages": ["packages/*"]
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/repo",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "postinstall": "expo-yarn-workspaces check-workspace-dependencies",
7 | "gen": "ts-node ./scripts/generate-plugin.ts",
8 | "update-issue-template": "ts-node ./scripts/gh-issues-config.ts",
9 | "update-dependabot-config": "ts-node ./scripts/update-dependabot-config.ts",
10 | "start": "lerna run build --parallel -- --watch",
11 | "publish": "lerna publish --no-private",
12 | "prepare": "lerna run prepare --parallel"
13 | },
14 | "workspaces": [
15 | "apps/*",
16 | "packages/*"
17 | ],
18 | "resolutions": {
19 | "expo": "^53"
20 | },
21 | "devDependencies": {
22 | "@babel/core": "^7.25.2",
23 | "@expo/package-manager": "^1.8.4",
24 | "@types/js-yaml": "^4.0.5",
25 | "@types/prompts": "^2.0.13",
26 | "@types/react": "~18.3.12",
27 | "eslint": "^8.10.0",
28 | "expo-module-scripts": "^4.1.6",
29 | "expo-yarn-workspaces": "^2.3.2",
30 | "js-yaml": "^4.1.0",
31 | "memfs": "^3.4.4",
32 | "lerna": "3.4.1",
33 | "prettier": "^3",
34 | "prompts": "^2.4.1",
35 | "remark-cli": "^9.0.0",
36 | "remark-validate-links": "^10.0.2",
37 | "string.prototype.replaceall": "^1.0.5",
38 | "ts-node": "^10.0.0",
39 | "typescript": "^5.1.3"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/android-jsc-intl/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/android-jsc-intl/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/android-jsc-intl 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ## @config-plugins/android-jsc-intl [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/android-jsc-intl@1.0.4...@config-plugins/android-jsc-intl@2.0.0) (2022-05-10)
6 |
7 | ### ⚠ BREAKING CHANGES
8 |
9 | - **android-jsc-intl:** add SDK 45 support (#77)
10 |
11 | ### Features
12 |
13 | - **android-jsc-intl:** add SDK 45 support ([#77](https://github.com/expo/config-plugins/issues/77)) ([aed0904](https://github.com/expo/config-plugins/commit/aed09045d61bc67b375a277b96bdc90ed5245d0f))
14 |
15 | ### @config-plugins/android-jsc-intl [1.0.4](https://github.com/expo/config-plugins/compare/@config-plugins/android-jsc-intl@1.0.3...@config-plugins/android-jsc-intl@1.0.4) (2022-03-23)
16 |
17 | ### Other chores
18 |
19 | - **android-jsc-intl:** lint fix ([5ca4e44](https://github.com/expo/config-plugins/commit/5ca4e44a49ad5c3153b4a2b15acf69db594d76b8))
20 |
21 | ### @config-plugins/android-jsc-intl [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/android-jsc-intl@1.0.2...@config-plugins/android-jsc-intl@1.0.3) (2022-03-22)
22 |
23 | ### Other chores
24 |
25 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
26 |
27 | ### @config-plugins/android-jsc-intl [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/android-jsc-intl@1.0.1...@config-plugins/android-jsc-intl@1.0.2) (2022-03-16)
28 |
29 | ### Continuous Integration
30 |
31 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
32 |
33 | ### @config-plugins/android-jsc-intl [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/android-jsc-intl@1.0.0...@config-plugins/android-jsc-intl@1.0.1) (2022-03-15)
34 |
35 | ### Bug Fixes
36 |
37 | - **ci:** use correct internal versions ([ab8076a](https://github.com/expo/config-plugins/commit/ab8076adf51e9ba0439eba60b153d729a0996b8d))
38 |
39 | ## @config-plugins/android-jsc-intl 1.0.0 (2022-03-15)
40 |
41 | ### Features
42 |
43 | - Intl support for android via withAndroidJscIntl ([eb6642c](https://github.com/expo/config-plugins/commit/eb6642c0e7b37d6d9baf196ec40cc520f559e665))
44 |
45 | ### Bug Fixes
46 |
47 | - remove createPluginOnce ([68cf1c0](https://github.com/expo/config-plugins/commit/68cf1c07b2c48249cbbd0732668ea95455636a0b))
48 | - run expo prepare ([8d364ed](https://github.com/expo/config-plugins/commit/8d364ed99ea4b0e0e3af73dbcc780819bf55d6c2))
49 |
50 | ### Other chores
51 |
52 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
53 |
54 | ### Documentation changes
55 |
56 | - clarify readme ([b524633](https://github.com/expo/config-plugins/commit/b5246338cb37ae41d138bc6253703b0d438fc3e3))
57 |
--------------------------------------------------------------------------------
/packages/android-jsc-intl/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/android-jsc-intl
2 |
3 | Expo Config Plugin to auto-configure Android JSC Intl when the native code is generated (`npx expo prebuild`).
4 |
5 | Adding this plugin lets you use `Intl` in your Android app, without using Hermes.
6 |
7 | ## Expo installation
8 |
9 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
10 |
11 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
12 |
13 | ```sh
14 | npx expo install @config-plugins/android-jsc-intl
15 | ```
16 |
17 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
18 |
19 | ```json
20 | {
21 | "plugins": ["@config-plugins/android-jsc-intl"]
22 | }
23 | ```
24 |
25 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
26 |
--------------------------------------------------------------------------------
/packages/android-jsc-intl/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withAndroidJscIntl");
--------------------------------------------------------------------------------
/packages/android-jsc-intl/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/android-jsc-intl",
3 | "version": "11.0.0",
4 | "description": "Config plugin for android-jsc-intl package",
5 | "main": "build/withAndroidJscIntl.js",
6 | "types": "build/withAndroidJscIntl.d.ts",
7 | "sideEffects": false,
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/expo/config-plugins.git",
11 | "directory": "packages/android-jsc-intl"
12 | },
13 | "scripts": {
14 | "build": "expo-module build",
15 | "clean": "expo-module clean",
16 | "lint": "expo-module lint",
17 | "test": "expo-module test",
18 | "prepare": "expo-module prepare",
19 | "prepublishOnly": "expo-module prepublishOnly",
20 | "expo-module": "expo-module"
21 | },
22 | "keywords": [
23 | "react",
24 | "expo",
25 | "config-plugins",
26 | "prebuild",
27 | "android-jsc-intl"
28 | ],
29 | "peerDependencies": {
30 | "expo": "^53"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/android-jsc-intl/src/withAndroidJscIntl.ts:
--------------------------------------------------------------------------------
1 | import { type ConfigPlugin, withAppBuildGradle } from "expo/config-plugins";
2 |
3 | /**
4 | * Apply android-jsc-intl native configuration.
5 | *
6 | * This plugin lets you access the `Intl` API in Android apps (without Hermes).
7 | */
8 | const withAndroidJscIntl: ConfigPlugin = (config) =>
9 | withAppBuildGradle(config, (config) => {
10 | if (config.modResults.language !== "groovy") {
11 | throw new Error(
12 | "[@expo/config-plugins][withAndroidJscIntl] Cannot enable Intl in Android JSC app gradle because the build.gradle is not groovy.",
13 | );
14 | }
15 |
16 | config.modResults.contents = config.modResults.contents.replace(
17 | "org.webkit:android-jsc:+",
18 | "org.webkit:android-jsc-intl:+",
19 | );
20 |
21 | return config;
22 | });
23 |
24 | export default withAndroidJscIntl;
25 |
--------------------------------------------------------------------------------
/packages/android-jsc-intl/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "build",
5 | "rootDir": "src",
6 | "types": ["node", "jest"]
7 | },
8 | "include": ["./src"],
9 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/apple-settings/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/apple-settings/__mocks__/@expo/image-utils.ts:
--------------------------------------------------------------------------------
1 | export const generateImageAsync = jest.fn(async (input: any, { src }) => {
2 | const fs = require("fs");
3 | return { source: fs.readFileSync(src) };
4 | });
5 |
6 | export const compositeImagesAsync = jest.fn(async ({ foreground }) => {
7 | return foreground;
8 | });
9 |
--------------------------------------------------------------------------------
/packages/apple-settings/__mocks__/fs.ts:
--------------------------------------------------------------------------------
1 | import { fs } from 'memfs';
2 | module.exports = fs;
3 |
--------------------------------------------------------------------------------
/packages/apple-settings/jest.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | const roots = ["__mocks__", "src"];
4 |
5 | module.exports = {
6 | ...require("expo-module-scripts/jest-preset-plugin"),
7 | rootDir: path.resolve(__dirname),
8 | displayName: require("./package").name,
9 | roots,
10 | setupFiles: ["/jest/setup.js"],
11 | clearMocks: true,
12 | };
13 |
--------------------------------------------------------------------------------
/packages/apple-settings/jest/setup.js:
--------------------------------------------------------------------------------
1 | jest.mock("@expo/image-utils");
2 | jest.mock("fs");
3 |
--------------------------------------------------------------------------------
/packages/apple-settings/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/apple-settings",
3 | "version": "5.0.0",
4 | "description": "Config plugin to generate custom Apple settings UI",
5 | "license": "MIT",
6 | "main": "build/index.js",
7 | "types": "build/index.d.ts",
8 | "sideEffects": false,
9 | "files": [
10 | "build"
11 | ],
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/expo/config-plugins.git",
15 | "directory": "packages/apple-settings"
16 | },
17 | "scripts": {
18 | "build": "expo-module build",
19 | "clean": "expo-module clean",
20 | "lint": "expo-module lint",
21 | "test": "expo-module test",
22 | "generate-types": "json2ts -i ./src/schema/SettingsPlist.json -o ./src/schema/SettingsPlist.ts --additionalProperties=false --unknownAny=false",
23 | "prepare": "expo-module prepare && yarn generate-types",
24 | "prepublishOnly": "expo-module prepublishOnly",
25 | "expo-module": "expo-module"
26 | },
27 | "keywords": [
28 | "react",
29 | "expo"
30 | ],
31 | "dependencies": {
32 | "@bacons/xcode": "^1.0.0-alpha.12",
33 | "@expo/plist": "^0.3.4",
34 | "iconv-lite": "^0.6.3",
35 | "schema-utils": "^4.2.0"
36 | },
37 | "peerDependencies": {
38 | "expo": "^53"
39 | },
40 | "devDependencies": {
41 | "json-schema-to-typescript": "^13.0.2"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/base-mods/strings.ts:
--------------------------------------------------------------------------------
1 | // Ports https://github.com/iteufel/node-strings-file/blob/master/index.js to TyeScript and ESM:
2 |
3 | import fs from "fs";
4 | import iconv from "iconv-lite";
5 |
6 | type ParsedStrings = {
7 | [key: string]: string | { value: string; comment: string };
8 | };
9 |
10 | export function parse(data: string, wantComments?: boolean): ParsedStrings {
11 | if (data.indexOf("\n") === -1) {
12 | data += "\n";
13 | }
14 | const re = /(?:\/\*(.+)\*\/\n)?(.+)\s*=\s*"(.+)";\n/gim;
15 | const res: ParsedStrings = {};
16 | let m: RegExpExecArray | null;
17 |
18 | while ((m = re.exec(data)) !== null) {
19 | if (m.index === re.lastIndex) {
20 | re.lastIndex++;
21 | }
22 | if (m[2].substring(0, 1) === '"') {
23 | m[2] = m[2].trim().slice(1, -1);
24 | }
25 | if (wantComments) {
26 | res[m[2]] = {
27 | value: unescapeString(m[3]),
28 | comment: m[1] || "",
29 | };
30 | } else {
31 | res[m[2]] = unescapeString(m[3]);
32 | }
33 | }
34 | return res;
35 | }
36 |
37 | export function build(obj: ParsedStrings): string {
38 | let data = "";
39 | for (const i in obj) {
40 | if (typeof obj[i] === "object") {
41 | if (obj[i]["comment"] && obj[i]["comment"].length > 0) {
42 | data += `\n/*${obj[i]["comment"]}*/\n`;
43 | }
44 | data += `"${i}" = "${escapeString(obj[i]["value"])}";\n`;
45 | } else if (typeof obj[i] === "string") {
46 | data += `\n"${i}" = "${escapeString(obj[i])}";\n`;
47 | }
48 | }
49 | return data;
50 | }
51 |
52 | function escapeString(str: string): string {
53 | return str.replace(/"/gim, '\\"');
54 | }
55 |
56 | function unescapeString(str: string): string {
57 | return str.replace(/\\"/gim, '"');
58 | }
59 |
60 | export async function openAsync(file: string, wantComments?: boolean) {
61 | const data = await fs.promises.readFile(file);
62 | return parse(iconv.decode(data, "utf-16"), wantComments);
63 | }
64 |
65 | export function writeAsync(filename: string, data: ParsedStrings) {
66 | return fs.promises.writeFile(
67 | filename,
68 | iconv.encode(build(data), "utf-16"),
69 | "binary",
70 | );
71 | }
72 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/base-mods/withSettingsPlist.ts:
--------------------------------------------------------------------------------
1 | import * as plist from "@expo/plist";
2 | import {
3 | BaseMods,
4 | type ConfigPlugin,
5 | createRunOncePlugin,
6 | type Mod,
7 | withMod,
8 | } from "expo/config-plugins";
9 | import * as fs from "fs";
10 | import path from "path";
11 | import { validate } from "schema-utils";
12 |
13 | import { SettingsPlist } from "../schema/SettingsPlist";
14 | import schema from "../schema/SettingsPlist.json";
15 |
16 | export function createModSetForSettingsPage({ name }: { name: string }) {
17 | const customModName = "settings" + name + "Plist";
18 |
19 | const withSettingsPlist: ConfigPlugin> = (
20 | config,
21 | action,
22 | ) => {
23 | return withMod(config, {
24 | platform: "ios",
25 | mod: customModName,
26 | action,
27 | });
28 | };
29 |
30 | const withBaseModInternal: ConfigPlugin = (config) => {
31 | return BaseMods.withGeneratedBaseMods(config, {
32 | platform: "ios",
33 | saveToInternal: true,
34 | skipEmptyMod: false,
35 | providers: {
36 | [customModName]: BaseMods.provider({
37 | isIntrospective: true,
38 |
39 | async getFilePath({ modRequest }) {
40 | return path.join(
41 | modRequest.platformProjectRoot,
42 | modRequest.projectName!,
43 | `Settings.bundle/${name}.plist`,
44 | );
45 | },
46 | async read(filePath) {
47 | try {
48 | if (fs.existsSync(filePath) === false) {
49 | return {
50 | PreferenceSpecifiers: [],
51 | };
52 | }
53 | return plist.default.parse(
54 | await fs.promises.readFile(filePath, "utf-8"),
55 | );
56 | } catch (error: any) {
57 | throw new Error(
58 | `Failed to parse the iOS Settings.bundle/${name}.plist: "${filePath}". ${error.message}}`,
59 | );
60 | }
61 | },
62 | async write(filePath, { modResults, modRequest: { introspect } }) {
63 | // Perform strict validation.
64 | validate(schema as any, modResults);
65 |
66 | if (introspect) {
67 | return;
68 | }
69 | const contents = plist.default.build(modResults);
70 | // Ensure Settings.bundle
71 | await fs.promises.mkdir(path.dirname(filePath), {
72 | recursive: true,
73 | });
74 | await fs.promises.writeFile(filePath, contents);
75 | },
76 | }),
77 | },
78 | });
79 | };
80 |
81 | const baseName = `withAppleSettings${name}PlistBaseMod`;
82 |
83 | return {
84 | withSettingsPlist,
85 | withBaseMod: createRunOncePlugin(withBaseModInternal, baseName),
86 | };
87 | }
88 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/base-mods/withSettingsStrings.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type ConfigPlugin,
3 | type Mod,
4 | BaseMods,
5 | createRunOncePlugin,
6 | withMod,
7 | } from "expo/config-plugins";
8 | import * as fs from "fs";
9 | import path from "path";
10 |
11 | import * as strings from "./strings";
12 |
13 | export type SettingsStrings = Record;
14 |
15 | export function createModSetForSettingsStrings({
16 | name,
17 | lang = "en",
18 | }: {
19 | /** Like `Root` */
20 | name: string;
21 | /** Like `en` */
22 | lang?: string;
23 | }) {
24 | const customModName = "settings" + lang + "_" + name + "Strings";
25 |
26 | const withBaseModInternal: ConfigPlugin = (config) => {
27 | return BaseMods.withGeneratedBaseMods(config, {
28 | platform: "ios",
29 | saveToInternal: true,
30 | skipEmptyMod: false,
31 | providers: {
32 | [customModName]: BaseMods.provider({
33 | isIntrospective: true,
34 | async getFilePath({ modRequest }) {
35 | return path.join(
36 | modRequest.platformProjectRoot,
37 | modRequest.projectName!,
38 | `Settings.bundle/${lang}.lproj/${name}.strings`,
39 | );
40 | },
41 | async read(filePath) {
42 | try {
43 | if (fs.existsSync(filePath) === false) {
44 | return {};
45 | }
46 | return strings.openAsync(filePath, false) as unknown as Record<
47 | string,
48 | string
49 | >;
50 | } catch (error: any) {
51 | throw new Error(
52 | `Failed to parse the Settings.bundle/${lang}.lproj/${name}.strings: "${filePath}". ${error.message}}`,
53 | );
54 | }
55 | },
56 | async write(filePath, { modResults, modRequest: { introspect } }) {
57 | if (introspect) {
58 | return;
59 | }
60 | // Ensure Settings.bundle/en.lproj
61 | await fs.promises.mkdir(path.dirname(filePath), {
62 | recursive: true,
63 | });
64 | await strings.writeAsync(filePath, modResults);
65 | },
66 | }),
67 | },
68 | });
69 | };
70 |
71 | const withStrings: ConfigPlugin> = (config, action) => {
72 | return withMod(config, {
73 | platform: "ios",
74 | mod: customModName,
75 | action,
76 | });
77 | };
78 |
79 | const baseName = `withAppleSettings${lang}_${name}StringsBaseMod`;
80 |
81 | return {
82 | withStrings,
83 | withBaseMod: createRunOncePlugin(withBaseModInternal, baseName),
84 | };
85 | }
86 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/base-mods/withXcparse.ts:
--------------------------------------------------------------------------------
1 | import { XcodeProject } from "@bacons/xcode";
2 | import * as xcodeParse from "@bacons/xcode/json";
3 | import {
4 | type Mod,
5 | BaseMods,
6 | ConfigPlugin,
7 | createRunOncePlugin,
8 | IOSConfig,
9 | withMod,
10 | } from "expo/config-plugins";
11 | import * as fs from "fs";
12 |
13 | const customModName = "xcodeProjectBeta-apple-settings";
14 |
15 | export const withXcodeProjectBeta: ConfigPlugin> = (
16 | config,
17 | action,
18 | ) => {
19 | return withMod(config, {
20 | platform: "ios",
21 | mod: customModName,
22 | action,
23 | });
24 | };
25 |
26 | const withXcodeProjectBetaBaseModInternal: ConfigPlugin = (config) => {
27 | return BaseMods.withGeneratedBaseMods(config, {
28 | platform: "ios",
29 | saveToInternal: true,
30 | skipEmptyMod: false,
31 | providers: {
32 | // Append a custom rule to supply AppDelegate header data to mods on `mods.ios.AppClipInfoPlist`
33 | [customModName]: BaseMods.provider({
34 | isIntrospective: false,
35 | // isIntrospective: true,
36 | async getFilePath({ _internal }) {
37 | return IOSConfig.Paths.getPBXProjectPath(_internal!.projectRoot);
38 | },
39 | async read(filePath) {
40 | try {
41 | return XcodeProject.open(filePath);
42 | } catch (error: any) {
43 | throw new Error(
44 | `Failed to parse the Xcode project: "${filePath}". ${error.message}}`,
45 | );
46 | }
47 | },
48 | async write(filePath, { modResults, modRequest: { introspect } }) {
49 | if (introspect) {
50 | return;
51 | }
52 | const contents = xcodeParse.build(modResults.toJSON());
53 | if (contents.trim().length) {
54 | await fs.promises.writeFile(filePath, contents);
55 | }
56 | },
57 | }),
58 | },
59 | });
60 | };
61 |
62 | export const withXcodeProjectBetaBaseMod = createRunOncePlugin(
63 | withXcodeProjectBetaBaseModInternal,
64 | "withXcodeProjectBetaBaseMod",
65 | );
66 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/index.tsx:
--------------------------------------------------------------------------------
1 | import { withStaticSettings, StaticSettings, AppleLocale } from "./static";
2 |
3 | export {
4 | ChildPane,
5 | Group,
6 | RadioGroup,
7 | Slider,
8 | Switch,
9 | TextField,
10 | Title,
11 | MultiValue,
12 | } from "./models";
13 |
14 | export { StaticSettings, AppleLocale };
15 |
16 | export * from "./schema/SettingsPlist";
17 |
18 | export default withStaticSettings;
19 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/static.ts:
--------------------------------------------------------------------------------
1 | import { type ConfigPlugin, withPlugins } from "expo/config-plugins";
2 |
3 | import { createModSetForSettingsPage } from "./base-mods/withSettingsPlist";
4 | import { createModSetForSettingsStrings } from "./base-mods/withSettingsStrings";
5 | import { withXcodeProjectBetaBaseMod } from "./base-mods/withXcparse";
6 | import { SettingsPlist } from "./schema/SettingsPlist";
7 | import { withLinkedSettingsBundle } from "./withLinkedSettingsBundle";
8 |
9 | /**
10 | * Locale codes used in `lproj` directories for Apple software.
11 | * **Related:**
12 | * - [Swift locale interpretation routine](https://github.com/apple/swift-corelibs-foundation/blob/main/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c)
13 | * - [Preferences doc](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/UserDefaults/Preferences/Preferences.html#//apple_ref/doc/uid/10000059i-CH6-SW9)
14 | */
15 | export type AppleLocale =
16 | | "ar"
17 | | "ca"
18 | | "zh_Hans"
19 | | "zh_Hant"
20 | | "zh_HK"
21 | | "hr"
22 | | "cs"
23 | | "da"
24 | | "nl"
25 | | "en"
26 | | "en_GB"
27 | | "en_AU"
28 | | "en_CA"
29 | | "en_IN"
30 | | "en_IE"
31 | | "en_NZ"
32 | | "en_SG"
33 | | "en_ZA"
34 | | "fi"
35 | | "fr"
36 | | "fr_CA"
37 | | "de"
38 | | "el"
39 | | "he"
40 | | "hi"
41 | | "hu"
42 | | "id"
43 | | "it"
44 | | "ja"
45 | | "ko"
46 | | "ms"
47 | | "nb"
48 | | "pl"
49 | | "pt"
50 | | "pt_BR"
51 | | "ro"
52 | | "ru"
53 | | "sk"
54 | | "es"
55 | | "es_419"
56 | | "es_MX"
57 | | "sv"
58 | | "th"
59 | | "tr"
60 | | "uk"
61 | | "vi";
62 |
63 | export type StaticSettings = Record<
64 | /** Name of the file / bundle. */
65 | string,
66 | {
67 | /** Plist contents */
68 | page: SettingsPlist;
69 | /** Linked locales that will be written as a `*.strings` file (without comments). */
70 | locales?: Record<
71 | /** Apple locale code. */
72 | AppleLocale,
73 | /** Strings content with key/value. */
74 | Record
75 | >;
76 | }
77 | >;
78 |
79 | export const withStaticSettings: ConfigPlugin<
80 | Record<
81 | string,
82 | { page: SettingsPlist; locales?: Record> }
83 | >
84 | > = (config, panes) => {
85 | if (!panes || !("Root" in panes)) {
86 | throw new Error("Panes must include a 'Root' pane");
87 | }
88 |
89 | const postMods: any[] = [];
90 |
91 | Object.entries(panes).map(([key, pane]) => {
92 | const mods = createModSetForSettingsPage({
93 | // e.g. "Root"
94 | name: key,
95 | });
96 |
97 | const locales = pane.locales || {};
98 |
99 | if (Object.keys(locales).length) {
100 | const name = pane.page.StringsTable ?? key;
101 | pane.page.StringsTable = name;
102 |
103 | Object.entries(locales).map(([lang, strings]) => {
104 | const stringsMods = createModSetForSettingsStrings({
105 | name,
106 | lang,
107 | });
108 |
109 | stringsMods.withStrings(config, (config) => {
110 | config.modResults = strings;
111 |
112 | return config;
113 | });
114 |
115 | postMods.push(stringsMods.withBaseMod);
116 | });
117 | } else {
118 | // Allow using the default strings table.
119 | // delete pane.page.StringsTable;
120 | }
121 |
122 | config = mods.withSettingsPlist(config, (config) => {
123 | config.modResults = pane.page;
124 |
125 | return config;
126 | });
127 |
128 | postMods.push(mods.withBaseMod);
129 | });
130 |
131 | // Link Settings.bundle to the Xcode project.
132 | withLinkedSettingsBundle(config);
133 |
134 | // These must be last...
135 | withXcodeProjectBetaBaseMod(config);
136 |
137 | return withPlugins(config, postMods);
138 | };
139 |
140 | export default withStaticSettings;
141 |
--------------------------------------------------------------------------------
/packages/apple-settings/src/withLinkedSettingsBundle.ts:
--------------------------------------------------------------------------------
1 | import {
2 | PBXFileReference,
3 | PBXResourcesBuildPhase,
4 | PBXNativeTarget,
5 | XcodeProject,
6 | } from "@bacons/xcode";
7 | import { type ConfigPlugin } from "expo/config-plugins";
8 | import path from "path";
9 |
10 | import { withXcodeProjectBeta } from "./base-mods/withXcparse";
11 |
12 | function getMainAppTarget(project: XcodeProject): PBXNativeTarget {
13 | const mainAppTarget = project.rootObject.props.targets.filter((target) => {
14 | if (
15 | PBXNativeTarget.is(target) &&
16 | target.props.productType === "com.apple.product-type.application"
17 | ) {
18 | return !(
19 | "WATCHOS_DEPLOYMENT_TARGET" in
20 | // @ts-expect-error
21 | getDefaultBuildConfigurationForTarget(target)?.props?.buildSettings
22 | );
23 | }
24 | return false;
25 | }) as PBXNativeTarget[];
26 |
27 | if (mainAppTarget.length > 1) {
28 | console.warn(
29 | `Multiple main app targets found, using first one: ${mainAppTarget
30 | .map((t) => t.getDisplayName())
31 | .join(", ")}}`,
32 | );
33 | }
34 |
35 | return mainAppTarget[0];
36 | }
37 |
38 | function getDefaultBuildConfigurationForTarget(target: PBXNativeTarget) {
39 | return target.props.buildConfigurationList.props.buildConfigurations.find(
40 | (config) =>
41 | config.props.name ===
42 | target.props.buildConfigurationList.props.defaultConfigurationName,
43 | );
44 | }
45 |
46 | export const withLinkedSettingsBundle: ConfigPlugin = (config) => {
47 | return withXcodeProjectBeta(config, (config) => {
48 | applyXcodeChanges(config.modResults, {
49 | projectName: config.modRequest.projectName!,
50 | });
51 | return config;
52 | });
53 | };
54 |
55 | async function applyXcodeChanges(
56 | project: XcodeProject,
57 | props: { projectName: string },
58 | ) {
59 | const mainAppTarget = getMainAppTarget(project);
60 | const mainResourceBuildPhase = mainAppTarget.getBuildPhase(
61 | PBXResourcesBuildPhase,
62 | );
63 |
64 | // Prevent duplicate.
65 | if (
66 | mainResourceBuildPhase?.props.files.find(
67 | (file) => file.props.fileRef.props.name === "Settings.bundle",
68 | )
69 | ) {
70 | return project;
71 | }
72 |
73 | const ref = PBXFileReference.create(project, {
74 | lastKnownFileType: "wrapper.plug-in",
75 | name: "Settings.bundle",
76 | path: path.join(props.projectName, "Settings.bundle"),
77 | sourceTree: "",
78 | });
79 |
80 | mainResourceBuildPhase?.createFile({
81 | fileRef: ref,
82 | });
83 |
84 | // Add Setting.bundle to the project display.
85 | project.rootObject.props.mainGroup.props.children.push(ref);
86 |
87 | return project;
88 | }
89 |
--------------------------------------------------------------------------------
/packages/apple-settings/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "resolveJsonModule": true
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/ios-stickers/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/ios-stickers/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/ios-stickers 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ### @config-plugins/ios-stickers [2.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/ios-stickers@2.0.1...@config-plugins/ios-stickers@2.0.2) (2022-06-30)
6 |
7 | ### Other chores
8 |
9 | - **deps-dev:** bump memfs in /packages/ios-stickers ([#83](https://github.com/expo/config-plugins/issues/83)) ([764a047](https://github.com/expo/config-plugins/commit/764a04710bea6e66dbc6d0065812acb1591435fb))
10 |
11 | ### @config-plugins/ios-stickers [2.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/ios-stickers@2.0.0...@config-plugins/ios-stickers@2.0.1) (2022-05-30)
12 |
13 | ### Bug Fixes
14 |
15 | - **ios-stickers:** fix app icon generation ([#82](https://github.com/expo/config-plugins/issues/82)) ([190c489](https://github.com/expo/config-plugins/commit/190c489b764f285dbbecfa42fd7ee953fc849dcb))
16 |
17 | ## @config-plugins/ios-stickers [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/ios-stickers@1.0.3...@config-plugins/ios-stickers@2.0.0) (2022-05-12)
18 |
19 | ### ⚠ BREAKING CHANGES
20 |
21 | - add SDK 45 support (#79)
22 |
23 | ### Features
24 |
25 | - add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
26 |
27 | ### @config-plugins/ios-stickers [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/ios-stickers@1.0.2...@config-plugins/ios-stickers@1.0.3) (2022-03-22)
28 |
29 | ### Other chores
30 |
31 | - **ios-stickers:** lint fix ([331ecb1](https://github.com/expo/config-plugins/commit/331ecb163f000578bc519ebe94f90d62374095d1))
32 |
33 | ### @config-plugins/ios-stickers [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/ios-stickers@1.0.1...@config-plugins/ios-stickers@1.0.2) (2022-03-22)
34 |
35 | ### Other chores
36 |
37 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
38 |
39 | ### @config-plugins/ios-stickers [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/ios-stickers@1.0.0...@config-plugins/ios-stickers@1.0.1) (2022-03-16)
40 |
41 | ### Continuous Integration
42 |
43 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
44 |
45 | ### Documentation changes
46 |
47 | - **ios-stickers:** add doc block ([#55](https://github.com/expo/config-plugins/issues/55)) ([c904bc6](https://github.com/expo/config-plugins/commit/c904bc6a5f410645696a0356b5c188b94f80c231))
48 |
49 | ## @config-plugins/ios-stickers 1.0.0 (2022-03-15)
50 |
51 | ### Other chores
52 |
53 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
54 |
--------------------------------------------------------------------------------
/packages/ios-stickers/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/ios-stickers
2 |
3 | Config plugin to auto-configure iOS iMessage stickers
4 |
5 | ## Versioning
6 |
7 | Ensure you use versions that work together!
8 |
9 | | `expo` | `@config-plugins/ios-stickers` |
10 | | ------ | ------------------------------ |
11 | | 53.0.0 | 10.0.0 |
12 | | 52.0.0 | 9.0.0 |
13 | | 51.0.0 | 8.0.0 |
14 | | 50.0.0 | 7.0.0 |
15 | | 49.0.0 | 6.0.0 |
16 |
17 | ## Install
18 |
19 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
20 |
21 | ```
22 | npx expo install @config-plugins/ios-stickers
23 | ```
24 |
25 | ## Example
26 |
27 | In your app.json `plugins` array:
28 |
29 | ```json
30 | {
31 | "plugins": [
32 | [
33 | "@config-plugins/ios-stickers",
34 | {
35 | "name": "Stickers!",
36 | "icon": "./assets/imessage-icon.png",
37 | "stickerBundleId": "dev.bacon.iosstickers.stickers",
38 | "columns": 4,
39 | "stickers": [
40 | "./assets/stickers/annoyed.png",
41 | "./assets/stickers/cuddle.png",
42 | "./assets/stickers/crazy.png",
43 | "./assets/stickers/cant.png",
44 | "./assets/stickers/donno.png",
45 | "./assets/stickers/cozzy.png",
46 | "./assets/stickers/dork.png",
47 | "./assets/stickers/focus.png",
48 | "./assets/stickers/avocool.png",
49 | "./assets/stickers/coder-girl.png",
50 | "./assets/stickers/teapot.png"
51 | ]
52 | }
53 | ]
54 | ]
55 | }
56 | ```
57 |
58 | - `name`: defaults to the iOS app name
59 | - `stickerBundleId`: custom bundle identifier for the stickers project, if not provided, it will defaults to `${ios.bundleIdentifier}.${name}-Stickers` given your expo config values.
60 | - `icon`: defaults to the iOS app icon
61 | - `columns`: number of stickers to render, defaults to `3`. Can be one of `2`, `3`, `4`.
62 | - `stickers`: local file paths or remote URLs, or `{ image: "...", name: "...", accessibilityLabel: "..." }`. Order is preserved.
63 |
--------------------------------------------------------------------------------
/packages/ios-stickers/__mocks__/@expo/image-utils.ts:
--------------------------------------------------------------------------------
1 | export const generateImageAsync = jest.fn(async (input: any, { src }) => {
2 | const fs = require("fs");
3 | return { source: fs.readFileSync(src) };
4 | });
5 |
6 | export const compositeImagesAsync = jest.fn(async ({ foreground }) => {
7 | return foreground;
8 | });
9 |
--------------------------------------------------------------------------------
/packages/ios-stickers/__mocks__/fs.ts:
--------------------------------------------------------------------------------
1 | import { fs } from 'memfs';
2 | module.exports = fs;
3 |
--------------------------------------------------------------------------------
/packages/ios-stickers/jest.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | const roots = ["__mocks__", "src"];
4 |
5 | module.exports = {
6 | ...require("expo-module-scripts/jest-preset-plugin"),
7 | rootDir: path.resolve(__dirname),
8 | displayName: require("./package").name,
9 | roots,
10 | setupFiles: ["/jest/setup.js"],
11 | clearMocks: true,
12 | };
13 |
--------------------------------------------------------------------------------
/packages/ios-stickers/jest/setup.js:
--------------------------------------------------------------------------------
1 | jest.mock("@expo/image-utils");
2 | jest.mock("fs");
3 |
--------------------------------------------------------------------------------
/packages/ios-stickers/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/ios-stickers",
3 | "version": "11.0.0",
4 | "description": "Config plugin to auto configure iOS iMessage stickers",
5 | "main": "build/withStickerPack.js",
6 | "types": "build/withStickerPack.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "files": [
10 | "build"
11 | ],
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/expo/config-plugins.git",
15 | "directory": "packages/ios-stickers"
16 | },
17 | "scripts": {
18 | "build": "expo-module build",
19 | "clean": "expo-module clean",
20 | "lint": "expo-module lint",
21 | "test": "expo-module test",
22 | "prepare": "expo-module prepare",
23 | "prepublishOnly": "expo-module prepublishOnly",
24 | "expo-module": "expo-module"
25 | },
26 | "keywords": [
27 | "react",
28 | "expo"
29 | ],
30 | "dependencies": {
31 | "schema-utils": "^4.0.0",
32 | "xcode": "^3.0.1"
33 | },
34 | "peerDependencies": {
35 | "expo": "^53"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/ios-stickers/src/__tests__/fixtures/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expo/config-plugins/566f54e785147d88cb4c98490c3e536ee7ef3001/packages/ios-stickers/src/__tests__/fixtures/icon.png
--------------------------------------------------------------------------------
/packages/ios-stickers/src/__tests__/generateImessageIconsAsync.test.ts:
--------------------------------------------------------------------------------
1 | import { generateImageAsync } from "@expo/image-utils";
2 | import fs from "fs";
3 | import { vol } from "memfs";
4 | import path from "path";
5 |
6 | import { generateImessageIconsAsync } from "../generateImessageIconsAsync";
7 |
8 | const fsReal = jest.requireActual("fs") as typeof fs;
9 |
10 | describe(generateImessageIconsAsync, () => {
11 | it(`should generate imessage icons`, async () => {
12 | vol.fromJSON({}, "/");
13 | await fs.promises.writeFile(
14 | "/icon.png",
15 | await fsReal.promises.readFile(path.join(__dirname, "fixtures/icon.png")),
16 | );
17 | const contents = await generateImessageIconsAsync(
18 | "/",
19 | "/icon.png",
20 | "/output",
21 | );
22 |
23 | expect(generateImageAsync).toHaveBeenCalledTimes(13);
24 |
25 | expect(contents).toEqual([
26 | {
27 | filename: "App-Icon-iphone-29x29@2x.png",
28 | idiom: "iphone",
29 | scale: "2x",
30 | size: "29x29",
31 | },
32 | {
33 | filename: "App-Icon-iphone-29x29@3x.png",
34 | idiom: "iphone",
35 | scale: "3x",
36 | size: "29x29",
37 | },
38 | {
39 | filename: "App-Icon-iphone-60x45@2x.png",
40 | idiom: "iphone",
41 | scale: "2x",
42 | size: "60x45",
43 | },
44 | {
45 | filename: "App-Icon-iphone-60x45@3x.png",
46 | idiom: "iphone",
47 | scale: "3x",
48 | size: "60x45",
49 | },
50 | {
51 | filename: "App-Icon-ipad-29x29@2x.png",
52 | idiom: "ipad",
53 | scale: "2x",
54 | size: "29x29",
55 | },
56 | {
57 | filename: "App-Icon-ipad-67x50@2x.png",
58 | idiom: "ipad",
59 | scale: "2x",
60 | size: "67x50",
61 | },
62 | {
63 | filename: "App-Icon-ipad-74x55@2x.png",
64 | idiom: "ipad",
65 | scale: "2x",
66 | size: "74x55",
67 | },
68 | {
69 | filename: "App-Icon-universal-27x20@2x.png",
70 | idiom: "universal",
71 | platform: "ios",
72 | scale: "2x",
73 | size: "27x20",
74 | },
75 | {
76 | filename: "App-Icon-universal-27x20@3x.png",
77 | idiom: "universal",
78 | platform: "ios",
79 | scale: "3x",
80 | size: "27x20",
81 | },
82 | {
83 | filename: "App-Icon-universal-32x24@2x.png",
84 | idiom: "universal",
85 | platform: "ios",
86 | scale: "2x",
87 | size: "32x24",
88 | },
89 | {
90 | filename: "App-Icon-universal-32x24@3x.png",
91 | idiom: "universal",
92 | platform: "ios",
93 | scale: "3x",
94 | size: "32x24",
95 | },
96 | {
97 | filename: "App-Icon-ios-marketing-1024x1024@1x.png",
98 | idiom: "ios-marketing",
99 | scale: "1x",
100 | size: "1024x1024",
101 | },
102 | {
103 | filename: "App-Icon-ios-marketing-1024x768@1x.png",
104 | idiom: "ios-marketing",
105 | platform: "ios",
106 | scale: "1x",
107 | size: "1024x768",
108 | },
109 | ]);
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/packages/ios-stickers/src/__tests__/withStickerPack-test.ts:
--------------------------------------------------------------------------------
1 | import withStickerPack from "../withStickerPack";
2 |
3 | const exp = { name: "foo", slug: "bar" };
4 | describe(withStickerPack, () => {
5 | it("should not throw when options are valid", () => {
6 | expect(() =>
7 | withStickerPack(exp, {
8 | name: "test",
9 | stickerBundleId: "test",
10 | stickers: [{ image: "test.png" }],
11 | columns: 2,
12 | icon: "test.png",
13 | }),
14 | ).not.toThrow();
15 | });
16 | it("should not throw when no options are provided", () => {
17 | expect(() => withStickerPack(exp, {})).not.toThrow();
18 | });
19 | it("should throw if columns is not a number", () => {
20 | expect(() => {
21 | withStickerPack(exp, {
22 | stickers: [],
23 | icon: "",
24 | name: "",
25 | columns: "3",
26 | } as any);
27 | }).toThrowErrorMatchingInlineSnapshot(`
28 | "Invalid options object. @config-plugins/ios-stickers has been initialized using an options object that does not match the API schema.
29 | - options.columns should be one of these:
30 | 2 | 3 | 4"
31 | `);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/packages/ios-stickers/src/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "@config-plugins/ios-stickers options",
3 | "$schema": "http://json-schema.org/draft-07/schema#",
4 | "$ref": "#/definitions/Props",
5 | "definitions": {
6 | "Props": {
7 | "type": "object",
8 | "properties": {
9 | "stickers": {
10 | "type": "array",
11 | "items": {
12 | "anyOf": [
13 | {
14 | "type": "string"
15 | },
16 | {
17 | "$ref": "#/definitions/Sticker"
18 | }
19 | ]
20 | }
21 | },
22 | "icon": {
23 | "type": "string"
24 | },
25 | "name": {
26 | "type": "string"
27 | },
28 | "stickerBundleId": {
29 | "type": "string"
30 | },
31 | "columns": {
32 | "type": "number",
33 | "enum": [
34 | 2,
35 | 3,
36 | 4
37 | ]
38 | }
39 | },
40 | "additionalProperties": false
41 | },
42 | "Sticker": {
43 | "type": "object",
44 | "properties": {
45 | "image": {
46 | "type": "string"
47 | },
48 | "name": {
49 | "type": "string"
50 | },
51 | "accessibilityLabel": {
52 | "type": "string"
53 | }
54 | },
55 | "required": [
56 | "image"
57 | ],
58 | "additionalProperties": false
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/packages/ios-stickers/src/withStickerInfoPlist.ts:
--------------------------------------------------------------------------------
1 | import plist from "@expo/plist";
2 | import {
3 | type ConfigPlugin,
4 | type InfoPlist,
5 | IOSConfig,
6 | withDangerousMod,
7 | } from "expo/config-plugins";
8 | import * as fs from "fs";
9 | import * as path from "path";
10 |
11 | import { Props } from "./withStickerAssets";
12 | import { getProjectStickersName } from "./withStickerXcodeTarget";
13 |
14 | export const withStickersPlist: ConfigPlugin> = (
15 | config,
16 | { name },
17 | ) => {
18 | return withDangerousMod(config, [
19 | "ios",
20 | async (config) => {
21 | const stickerPackName = getProjectStickersName(
22 | config.modRequest.projectName!,
23 | );
24 | const stickerRootPath = path.join(
25 | config.modRequest.platformProjectRoot,
26 | stickerPackName,
27 | );
28 | const filePath = path.join(stickerRootPath, "Info.plist");
29 |
30 | const stickers: InfoPlist = {
31 | CFBundleDevelopmentRegion: "$(DEVELOPMENT_LANGUAGE)",
32 | CFBundleExecutable: "$(EXECUTABLE_NAME)",
33 | CFBundleIdentifier: "$(PRODUCT_BUNDLE_IDENTIFIER)",
34 | CFBundleInfoDictionaryVersion: "6.0",
35 | CFBundleName: "$(PRODUCT_NAME)",
36 | CFBundlePackageType: "$(PRODUCT_BUNDLE_PACKAGE_TYPE)",
37 | NSExtension: {
38 | NSExtensionPointIdentifier: "com.apple.message-payload-provider",
39 | NSExtensionPrincipalClass: "StickerBrowserViewController",
40 | },
41 | };
42 |
43 | stickers.CFBundleDisplayName = name || stickerPackName;
44 |
45 | // The version numbers must match the main Info.plist
46 | stickers.CFBundleVersion = IOSConfig.Version.getBuildNumber(config);
47 | stickers.CFBundleShortVersionString =
48 | IOSConfig.Version.getVersion(config);
49 |
50 | await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
51 | await fs.promises.writeFile(filePath, plist.build(stickers));
52 |
53 | return config;
54 | },
55 | ]);
56 | };
57 |
--------------------------------------------------------------------------------
/packages/ios-stickers/src/withStickerPack.ts:
--------------------------------------------------------------------------------
1 | import { type ConfigPlugin } from "expo/config-plugins";
2 | import path from "path";
3 | import { validate } from "schema-utils";
4 |
5 | import schema from "./options.json";
6 | import { Props, Sticker, withStickerAssets } from "./withStickerAssets";
7 | import { withStickersPlist } from "./withStickerInfoPlist";
8 | import { withStickerXcodeTarget } from "./withStickerXcodeTarget";
9 |
10 | // TODO: Maybe the name is better to use as a prop...
11 | const sizeColumnMap: Record = {
12 | 4: "small",
13 | 3: "regular",
14 | 2: "large",
15 | };
16 |
17 | export function normalizeStickersProps(
18 | props: Props["stickers"] = [],
19 | ): Sticker[] {
20 | const imagesObj = props.map((prop) => {
21 | if (typeof prop === "string") {
22 | return { image: prop };
23 | }
24 | return prop;
25 | });
26 |
27 | // Apply names
28 | return imagesObj.map((sticker) => {
29 | sticker.name =
30 | sticker.name || path.basename(sticker.image, path.extname(sticker.image));
31 | return sticker;
32 | });
33 | }
34 |
35 | const withStickerPack: ConfigPlugin = (config, options = {}) => {
36 | // Perform option validation.
37 | validate(schema as any, options);
38 |
39 | const { stickers, icon, name, stickerBundleId, columns = 3 } = options;
40 |
41 | const size = sizeColumnMap[columns] || "regular";
42 | if (!size) {
43 | throw new Error(
44 | `Column size "${columns}" is invalid. Expected one of: ${Object.keys(
45 | sizeColumnMap,
46 | ).join(", ")}`,
47 | );
48 | }
49 | const _stickers = normalizeStickersProps(stickers);
50 |
51 | config = withStickersPlist(config, { name });
52 | config = withStickerAssets(config, { stickers: _stickers, icon, size });
53 | config = withStickerXcodeTarget(config, { stickerBundleId });
54 | return config;
55 | };
56 |
57 | export default withStickerPack;
58 |
--------------------------------------------------------------------------------
/packages/ios-stickers/src/withStickerXcodeTarget.ts:
--------------------------------------------------------------------------------
1 | import { type ConfigPlugin, withXcodeProject } from "expo/config-plugins";
2 |
3 | import { Props } from "./withStickerAssets";
4 | import {
5 | addStickerResourceFile,
6 | addStickersTarget,
7 | getMainPBXGroup,
8 | } from "./xcodeSticker";
9 |
10 | const STICKERS_ROOT_PATH = "Stickers.xcassets";
11 |
12 | export function getProjectStickersName(name: string) {
13 | return `${name} Stickers`;
14 | }
15 |
16 | export const withStickerXcodeTarget: ConfigPlugin<
17 | Pick
18 | > = (config, { stickerBundleId }) => {
19 | return withXcodeProject(config, (config) => {
20 | const stickerPackName = getProjectStickersName(
21 | config.modRequest.projectName!,
22 | );
23 |
24 | addStickersTarget(
25 | config.modResults,
26 | stickerPackName,
27 | config.ios!.bundleIdentifier!,
28 | stickerPackName,
29 | stickerBundleId,
30 | );
31 |
32 | const stickersKey = addStickerResourceFile(
33 | config.modResults,
34 | STICKERS_ROOT_PATH,
35 | stickerPackName,
36 | );
37 |
38 | if (stickersKey) {
39 | const mainGroup = getMainPBXGroup(config.modResults);
40 | if (mainGroup) {
41 | config.modResults.addToPbxGroup(stickersKey, mainGroup.id);
42 | }
43 | }
44 |
45 | return config;
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/packages/ios-stickers/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "resolveJsonModule": true
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-adjust 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ### @config-plugins/react-native-adjust [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-adjust@1.0.2...@config-plugins/react-native-adjust@1.0.3) (2022-03-23)
6 |
7 | ### Bug Fixes
8 |
9 | - upgrade google play-services-analytics to v18.0.1 ([a24ea1d](https://github.com/expo/config-plugins/commit/a24ea1df58e9d0639dc4fa016aae8a4e15d53529))
10 |
11 | ### @config-plugins/react-native-adjust [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-adjust@1.0.1...@config-plugins/react-native-adjust@1.0.2) (2022-03-22)
12 |
13 | ### Other chores
14 |
15 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
16 |
17 | ### @config-plugins/react-native-adjust [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-adjust@1.0.0...@config-plugins/react-native-adjust@1.0.1) (2022-03-16)
18 |
19 | ### Continuous Integration
20 |
21 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
22 |
23 | ## @config-plugins/react-native-adjust 1.0.0 (2022-03-15)
24 |
25 | ### Other chores
26 |
27 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
28 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/react-native-adjust
2 |
3 | Expo Config Plugin to auto-configure [`react-native-adjust`](https://www.npmjs.com/package/react-native-adjust) when the native code is generated (`npx expo prebuild`).
4 |
5 | ## Versioning
6 |
7 | Ensure you use versions that work together!
8 |
9 | | `expo` | `react-native-adjust` | `@config-plugins/react-native-adjust` |
10 | | ------ | --------------------- | ------------------------------------- |
11 | | 53.0.0 | 5.1.0 | 10.0.0 |
12 | | 52.0.0 | 5.0.2 | 9.0.0 |
13 | | 51.0.0 | 4.38.1 | 8.0.0 |
14 | | 50.0.0 | 4.37.1 | 7.0.0 |
15 | | 49.0.0 | 4.33.0 | 6.0.0 |
16 |
17 | ## Expo installation
18 |
19 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
20 |
21 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
22 |
23 | ```sh
24 | npx expo install react-native-adjust @config-plugins/react-native-adjust
25 | ```
26 |
27 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
28 |
29 | ```json
30 | {
31 | "plugins": ["@config-plugins/react-native-adjust"]
32 | }
33 | ```
34 |
35 | If you are targeting Android 12 and above (API level 31), you need to add it in the options of the plugin:
36 |
37 | ```json
38 | {
39 | "plugins": [
40 | ["@config-plugins/react-native-adjust", { "targetAndroid12": true }]
41 | ]
42 | }
43 | ```
44 |
45 | This will add the [appropriate permission](https://github.com/adjust/react_native_sdk#add-permission-to-gather-google-advertising-id) for you.
46 |
47 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
48 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withReactNativeAdjust");
2 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-adjust",
3 | "version": "11.0.0",
4 | "description": "Config plugin to auto configure Adjust SDK on prebuild",
5 | "main": "build/withReactNativeAdjust.js",
6 | "types": "build/withReactNativeAdjust.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-adjust"
13 | },
14 | "scripts": {
15 | "build": "expo-module build",
16 | "clean": "expo-module clean",
17 | "lint": "expo-module lint",
18 | "test": "expo-module test",
19 | "prepare": "expo-module prepare",
20 | "prepublishOnly": "expo-module prepublishOnly",
21 | "expo-module": "expo-module"
22 | },
23 | "keywords": [
24 | "react",
25 | "expo",
26 | "config-plugins",
27 | "prebuild",
28 | "react-native-adjust"
29 | ],
30 | "peerDependencies": {
31 | "expo": "^53"
32 | },
33 | "upstreamPackage": "react-native-adjust"
34 | }
35 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/src/withReactNativeAdjust.ts:
--------------------------------------------------------------------------------
1 | import { mergeContents } from "@expo/config-plugins/build/utils/generateCode";
2 | import {
3 | type ConfigPlugin,
4 | AndroidConfig,
5 | createRunOncePlugin,
6 | IOSConfig,
7 | withAppBuildGradle,
8 | withXcodeProject,
9 | } from "expo/config-plugins";
10 |
11 | const withXcodeLinkBinaryWithLibraries: ConfigPlugin<{
12 | library: string;
13 | status?: string;
14 | }> = (config, { library, status }) => {
15 | return withXcodeProject(config, (config) => {
16 | const options = status === "optional" ? { weak: true } : {};
17 |
18 | const target = IOSConfig.XcodeUtils.getApplicationNativeTarget({
19 | project: config.modResults,
20 | projectName: config.modRequest.projectName!,
21 | });
22 |
23 | config.modResults.addFramework(library, {
24 | target: target.uuid,
25 | ...options,
26 | });
27 |
28 | return config;
29 | });
30 | };
31 |
32 | const addAndroidPackagingOptions = (src: string) => {
33 | return mergeContents({
34 | tag: "react-native-play-services-analytics",
35 | src,
36 | newSrc: `
37 | implementation 'com.google.android.gms:play-services-analytics:18.0.1'
38 | implementation 'com.android.installreferrer:installreferrer:2.2'
39 | `,
40 | anchor: /dependencies(?:\s+)?\{/,
41 | // Inside the dependencies block.
42 | offset: 1,
43 | comment: "//",
44 | });
45 | };
46 |
47 | const withGradle: ConfigPlugin = (config) => {
48 | return withAppBuildGradle(config, (config) => {
49 | if (config.modResults.language === "groovy") {
50 | config.modResults.contents = addAndroidPackagingOptions(
51 | config.modResults.contents,
52 | ).contents;
53 | } else {
54 | throw new Error(
55 | "Cannot add Play Services maven gradle because the project build.gradle is not groovy",
56 | );
57 | }
58 | return config;
59 | });
60 | };
61 |
62 | /**
63 | * Apply react-native-adjust configuration for Expo SDK +44 projects.
64 | */
65 | const withAdjustPlugin: ConfigPlugin = (
66 | config,
67 | _props,
68 | ) => {
69 | const props = _props || {};
70 |
71 | config = withXcodeLinkBinaryWithLibraries(config, {
72 | library: "iAd.framework",
73 | status: "optional",
74 | });
75 |
76 | config = withXcodeLinkBinaryWithLibraries(config, {
77 | library: "AdServices.framework",
78 | status: "optional",
79 | });
80 |
81 | config = withXcodeLinkBinaryWithLibraries(config, {
82 | library: "AdSupport.framework",
83 | status: "optional",
84 | });
85 |
86 | config = withXcodeLinkBinaryWithLibraries(config, {
87 | library: "StoreKit.framework",
88 | status: "optional",
89 | });
90 |
91 | config = withXcodeLinkBinaryWithLibraries(config, {
92 | library: "AppTrackingTransparency.framework",
93 | status: "optional",
94 | });
95 |
96 | if (props.targetAndroid12) {
97 | config = AndroidConfig.Permissions.withPermissions(config, [
98 | "com.google.android.gms.permission.AD_ID",
99 | ]);
100 | }
101 |
102 | config = withGradle(config);
103 |
104 | // Return the modified config.
105 | return config;
106 | };
107 |
108 | const pkg = {
109 | // Prevent this plugin from being run more than once.
110 | // This pattern enables users to safely migrate off of this
111 | // out-of-tree `@config-plugins/react-native-adjust` to a future
112 | // upstream plugin in `react-native-adjust`
113 | name: "react-native-adjust",
114 | // Indicates that this plugin is dangerously linked to a module,
115 | // and might not work with the latest version of that module.
116 | version: "UNVERSIONED",
117 | };
118 |
119 | export default createRunOncePlugin(withAdjustPlugin, pkg.name, pkg.version);
120 |
--------------------------------------------------------------------------------
/packages/react-native-adjust/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "./build"
5 | },
6 | "include": ["./src"],
7 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/react-native-ble-plx/README.md:
--------------------------------------------------------------------------------
1 | # config-plugins/react-native-ble-plx
2 |
3 | > [!IMPORTANT] > `react-native-ble-plx` now has upstream support for Expo Config Plugins, this package is no longer necessary. Please remove it from your project and use the latest version of `react-native-ble-plx` instead.
4 |
5 | Config plugin to auto-configure `react-native-ble-plx` when the native code is generated (`npx expo prebuild`). [Upstream PR](https://github.com/Polidea/react-native-ble-plx/pull/842).
6 |
7 | ## Expo installation
8 |
9 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
10 |
11 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
12 |
13 | ```sh
14 | npx expo install react-native-ble-plx @config-plugins/react-native-ble-plx
15 | ```
16 |
17 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
18 |
19 | ```json
20 | {
21 | "expo": {
22 | "plugins": ["@config-plugins/react-native-ble-plx"]
23 | }
24 | }
25 | ```
26 |
27 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
28 |
29 | ## API
30 |
31 | The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
32 |
33 | - `isBackgroundEnabled` (_boolean_): Enable background BLE support on Android. Adds `` to the `AndroidManifest.xml`. Default `false`.
34 | - `neverForLocation` (_boolean_): Set to true only if you can strongly assert that your app never derives physical location from Bluetooth scan results. The location permission will be still required on older Android devices. Note, that some BLE beacons are filtered from the scan results. Android SDK 31+. Default `false`. _WARNING: This parameter is experimental and BLE might not work. Make sure to test before releasing to production._
35 | - `modes` (_string[]_): Adds iOS `UIBackgroundModes` to the `Info.plist`. Options are: `peripheral`, and `central`. Defaults to undefined.
36 | - `bluetoothAlwaysPermission` (_string | false_): Sets the iOS `NSBluetoothAlwaysUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission. Defaults to `Allow $(PRODUCT_NAME) to connect to bluetooth devices`.
37 |
38 | > Expo SDK 48 supports iOS 13+ which means `NSBluetoothPeripheralUsageDescription` is fully deprecated. It is no longer setup in `@config-plugins/react-native-ble-plx@5.0.0` and greater.
39 |
40 | #### Example
41 |
42 | ```json
43 | {
44 | "expo": {
45 | "plugins": [
46 | [
47 | "@config-plugins/react-native-ble-plx",
48 | {
49 | "isBackgroundEnabled": true,
50 | "modes": ["peripheral", "central"],
51 | "bluetoothAlwaysPermission": "Allow $(PRODUCT_NAME) to connect to bluetooth devices"
52 | }
53 | ]
54 | ]
55 | }
56 | }
57 | ```
58 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-blob-util 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ### @config-plugins/react-native-blob-util [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-blob-util@1.0.2...@config-plugins/react-native-blob-util@1.0.3) (2022-03-22)
6 |
7 | ### Other chores
8 |
9 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
10 |
11 | ### @config-plugins/react-native-blob-util [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-blob-util@1.0.1...@config-plugins/react-native-blob-util@1.0.2) (2022-03-16)
12 |
13 | ### Continuous Integration
14 |
15 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
16 |
17 | ### @config-plugins/react-native-blob-util [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-blob-util@1.0.0...@config-plugins/react-native-blob-util@1.0.1) (2022-03-15)
18 |
19 | ### Bug Fixes
20 |
21 | - **ci:** use correct internal versions ([ab8076a](https://github.com/expo/config-plugins/commit/ab8076adf51e9ba0439eba60b153d729a0996b8d))
22 |
23 | ## @config-plugins/react-native-blob-util 1.0.0 (2022-03-15)
24 |
25 | ### Other chores
26 |
27 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
28 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/README.md:
--------------------------------------------------------------------------------
1 | # config-plugins/react-native-blob-util
2 |
3 | Config plugin to auto-configure [`react-native-blob-util`][lib] when the native code is generated (`npx expo prebuild`).
4 |
5 | ## Versioning
6 |
7 | Ensure you use versions that work together!
8 |
9 | | `expo` | `react-native-blob-util` | `@config-plugins/react-native-blob-util` |
10 | | ------ | ------------------------ | ---------------------------------------- |
11 | | 53.0.0 | 0.21.2 | 10.0.0 |
12 | | 52.0.0 | 0.19.11 | 9.0.0 |
13 | | 51.0.0 | 0.19.9 | 8.0.0 |
14 | | 50.0.0 | 0.19.6 | 7.0.0 |
15 | | 49.0.0 | 0.18.3 | 6.0.0 |
16 | | 48.0.0 | 0.17.2 | 5.0.0 |
17 |
18 | ### Add the package to your npm dependencies
19 |
20 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
21 |
22 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
23 |
24 | ```
25 | npx expo install react-native-blob-util @config-plugins/react-native-blob-util
26 | ```
27 |
28 | This plugin is Android-only and required for `react-native-pdf`.
29 |
30 | [lib]: https://www.npmjs.com/package/react-native-blob-util
31 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withReactNativeBlobUtil");
2 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('expo-module-scripts/jest-preset-plugin');
2 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-blob-util",
3 | "version": "11.0.0",
4 | "description": "Config plugin to auto configure react-native-blob-util on prebuild",
5 | "main": "build/withReactNativeBlobUtil.js",
6 | "types": "build/withReactNativeBlobUtil.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-blob-util"
13 | },
14 | "files": [
15 | "build",
16 | "app.plugin.js"
17 | ],
18 | "scripts": {
19 | "build": "expo-module build",
20 | "clean": "expo-module clean",
21 | "lint": "expo-module lint",
22 | "test": "expo-module test",
23 | "prepare": "expo-module prepare",
24 | "prepublishOnly": "expo-module prepublishOnly",
25 | "expo-module": "expo-module"
26 | },
27 | "keywords": [
28 | "react-native-blob-util",
29 | "react-native",
30 | "expo"
31 | ],
32 | "peerDependencies": {
33 | "expo": "^53"
34 | },
35 | "upstreamPackage": "react-native-blob-util"
36 | }
37 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/src/__tests__/__snapshots__/withReactNativeBlobUtil-test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`appendDownloadCompleteAction should return manifest 1`] = `
4 | "
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | "
22 | `;
23 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/src/__tests__/withReactNativeBlobUtil-test.ts:
--------------------------------------------------------------------------------
1 | import { XML } from "expo/config-plugins";
2 |
3 | import {
4 | ensureBlobProviderAuthorityString,
5 | appendDownloadCompleteAction,
6 | ensureBlobProviderManifest,
7 | } from "../withReactNativeBlobUtil";
8 |
9 | const fixture = `
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | `;
27 |
28 | describe(appendDownloadCompleteAction, () => {
29 | it("should return manifest", async () => {
30 | const manifest = (await XML.parseXMLAsync(fixture)) as any;
31 | appendDownloadCompleteAction(manifest);
32 | const firstResults = XML.format(manifest);
33 | expect(firstResults).toMatchSnapshot();
34 | expect(firstResults).toMatch(
35 | //,
36 | );
37 |
38 | // Doesn't mutate original.
39 | appendDownloadCompleteAction(manifest);
40 | const secondResults = XML.format(manifest);
41 | expect(secondResults).toMatch(firstResults);
42 | });
43 | });
44 |
45 | describe(ensureBlobProviderManifest, () => {
46 | it("should ensure the provider is added", async () => {
47 | const manifest = (await XML.parseXMLAsync(fixture)) as any;
48 |
49 | const first = XML.format(ensureBlobProviderManifest(manifest));
50 | expect(first).toContain(
51 | '',
52 | );
53 |
54 | // Doesn't add duplicates
55 | expect(
56 | XML.format(
57 | ensureBlobProviderManifest(ensureBlobProviderManifest(manifest)),
58 | ),
59 | ).toEqual(first);
60 | });
61 | });
62 |
63 | describe(ensureBlobProviderAuthorityString, () => {
64 | it("should ensure provider", async () => {
65 | const res = ensureBlobProviderAuthorityString(
66 | { resources: {} },
67 | "app.bacon",
68 | );
69 | const result = XML.format(res);
70 | expect(result).toMatchInlineSnapshot(`
71 | "
72 | app.bacon
73 | "
74 | `);
75 |
76 | const next = ensureBlobProviderAuthorityString(res, "app.bacon");
77 | expect(XML.format(next)).toBe(result);
78 |
79 | expect(XML.format(ensureBlobProviderAuthorityString(next, "com.other")))
80 | .toMatchInlineSnapshot(`
81 | "
82 | com.other
83 | "
84 | `);
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/packages/react-native-blob-util/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "build",
5 | "rootDir": "src"
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react-native-branch/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-branch/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-branch 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ### @config-plugins/react-native-branch [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-branch@1.0.1...@config-plugins/react-native-branch@1.0.2) (2022-03-22)
6 |
7 | ### Other chores
8 |
9 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
10 |
11 | ### @config-plugins/react-native-branch [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-branch@1.0.0...@config-plugins/react-native-branch@1.0.1) (2022-03-16)
12 |
13 | ### Continuous Integration
14 |
15 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
16 |
17 | ## @config-plugins/react-native-branch 1.0.0 (2022-03-15)
18 |
19 | ### Features
20 |
21 | - create react-native-branch plugin ([0b06baa](https://github.com/expo/config-plugins/commit/0b06baa2b486c5e02d433a4ac785960934f403b9))
22 | - support for universalLinkDomains ([01ca879](https://github.com/expo/config-plugins/commit/01ca879ca3f6cebac1177d74969337819a5fc72d))
23 |
24 | ### Bug Fixes
25 |
26 | - added expo-module.config.json to files ([57d589b](https://github.com/expo/config-plugins/commit/57d589ba8ad60e057b34ad7b2f404f67e85896ab))
27 | - fixed MATCH_INIT for SDKv44 ([904741a](https://github.com/expo/config-plugins/commit/904741a3bdb02f5bb76ebcf44131f1698dad0831))
28 | - fixed missing files when publish ([ebb8666](https://github.com/expo/config-plugins/commit/ebb86666d6e61a70838048839b144c7217886d73))
29 | - removed proguard-rules.pro edit step ([e1159b4](https://github.com/expo/config-plugins/commit/e1159b4021ab722cf3998479e6a459374bdb5075))
30 | - updates from code-reviews ([597ffc3](https://github.com/expo/config-plugins/commit/597ffc3bd76517ac96c39b77d8b76e6aee2609dd))
31 | - **android:** added `onNewIntent` handler ([31ed997](https://github.com/expo/config-plugins/commit/31ed9978ca6c0a079341b5b4be5479a5e5633f79))
32 | - rename module ([7f0dd05](https://github.com/expo/config-plugins/commit/7f0dd05fdc15293b84606cb000bcd7321b418de8))
33 | - respect old config from expo-branch ([d0e0186](https://github.com/expo/config-plugins/commit/d0e018601c09c0e92191a4eb2998ab0e6fa1c6ec))
34 |
35 | ### Code Refactoring
36 |
37 | - **android:** migrate to new expo modules system ([1ac233e](https://github.com/expo/config-plugins/commit/1ac233eb432eaeeb7ead6723a4a232f86cfc8e50))
38 | - **ios:** migrate to new expo modules system ([a98a6e0](https://github.com/expo/config-plugins/commit/a98a6e022fc06f8b9c996e4e2b4a1d7aac830d8a))
39 | - update plugin to use CodeMod ([ae66cac](https://github.com/expo/config-plugins/commit/ae66cac141847e33add62cc30375620e1a5cc1d0))
40 |
41 | ### Other chores
42 |
43 | - apply suggestions from code review ([0ccc227](https://github.com/expo/config-plugins/commit/0ccc22771d5ecc97da7720c362ecf90a76e5de1c))
44 | - cleanup android gitignore ([c88609a](https://github.com/expo/config-plugins/commit/c88609a8666be1b4137a3694bd844bb6a0f1ec12))
45 | - latest cleanup ([ef50c05](https://github.com/expo/config-plugins/commit/ef50c05892b965e2ccd70418da962f2c3d96ab2e))
46 | - rename files to avoid possible conflict ([d0b32ce](https://github.com/expo/config-plugins/commit/d0b32ce4a1c28060e61e7109f59be215c5f92f14))
47 | - rename module ([71e429b](https://github.com/expo/config-plugins/commit/71e429b77fca05953e94636b31e9b1b8da2ddcb6))
48 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
49 |
--------------------------------------------------------------------------------
/packages/react-native-branch/README.md:
--------------------------------------------------------------------------------
1 | # config-plugins/react-native-branch
2 |
3 | Config plugin to auto-configure `react-native-branch` when the native code is generated (`npx expo prebuild`).
4 |
5 | ## Versioning
6 |
7 | Ensure you use versions that work together!
8 |
9 | | `expo` | `react-native-branch` | `@config-plugins/react-native-branch` |
10 | | ------ | --------------------- | ------------------------------------- |
11 | | 52.0.0 | 6.4.0 | 9.0.0 |
12 | | 51.0.0 | 6.2.1 | 8.0.0 |
13 | | 50.0.0 | 6.0.0 | 7.0.0 |
14 | | 49.0.0 | 5.9.0 | 6.0.0 |
15 | | 48.0.0 | 5.7.0 | 5.0.0 |
16 |
17 | ## Expo installation
18 |
19 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
20 |
21 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
22 |
23 | ```sh
24 | npx expo install react-native-branch @config-plugins/react-native-branch
25 | ```
26 |
27 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
28 |
29 | ```json
30 | {
31 | "plugins": ["@config-plugins/react-native-branch"]
32 | }
33 | ```
34 |
35 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
36 |
37 | ## API
38 |
39 | The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
40 |
41 | - `apiKey` (_string_): Branch API key. Optional.
42 | - `iosAppDomain` (_string_): App Domain for iOS. Optional.
43 |
44 | #### Example
45 |
46 | ```json
47 | {
48 | "plugins": [
49 | [
50 | "@config-plugins/react-native-branch",
51 | {
52 | "apiKey": "key_live_f9f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8",
53 | "iosAppDomain": "awesome-alternate.app.link"
54 | }
55 | ]
56 | ]
57 | }
58 | ```
59 |
--------------------------------------------------------------------------------
/packages/react-native-branch/android/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle files
2 | .gradle/
3 | build/
4 |
--------------------------------------------------------------------------------
/packages/react-native-branch/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | group = 'host.exp.exponent'
4 | version = '5.0.0'
5 |
6 | def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7 | apply from: expoModulesCorePlugin
8 | applyKotlinExpoModulesCorePlugin()
9 | useCoreDependencies()
10 | useDefaultAndroidSdkVersions()
11 | useExpoPublishing()
12 |
13 | android {
14 | namespace "expo.modules.adapters.branch"
15 | defaultConfig {
16 | versionCode 5
17 | versionName '5.0.0'
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation 'com.facebook.react:react-android'
23 | implementation project(':react-native-branch')
24 | }
25 |
--------------------------------------------------------------------------------
/packages/react-native-branch/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/packages/react-native-branch/android/src/main/java/expo/modules/adapters/branch/BranchApplicationLifecycleListener.kt:
--------------------------------------------------------------------------------
1 | package expo.modules.adapters.branch
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import expo.modules.core.interfaces.ApplicationLifecycleListener
6 | import io.branch.rnbranch.RNBranchModule
7 |
8 | class BranchApplicationLifecycleListener(context: Context?) : ApplicationLifecycleListener {
9 | var context = context
10 |
11 | override fun onCreate(application: Application) {
12 | super.onCreate(application)
13 | RNBranchModule.getAutoInstance(this.context)
14 | }
15 | }
--------------------------------------------------------------------------------
/packages/react-native-branch/android/src/main/java/expo/modules/adapters/branch/BranchPackage.kt:
--------------------------------------------------------------------------------
1 | package expo.modules.adapters.branch
2 |
3 | import android.content.Context
4 | import expo.modules.core.interfaces.ApplicationLifecycleListener
5 | import expo.modules.core.interfaces.Package
6 | import expo.modules.core.interfaces.ReactActivityLifecycleListener
7 |
8 | class BranchPackage : Package {
9 | override fun createApplicationLifecycleListeners(context: Context?): List {
10 | return listOf(BranchApplicationLifecycleListener(context))
11 | }
12 | override fun createReactActivityLifecycleListeners(activityContext: Context): List {
13 | return listOf(BranchReactActivityLifecycleListener(activityContext))
14 | }
15 | }
--------------------------------------------------------------------------------
/packages/react-native-branch/android/src/main/java/expo/modules/adapters/branch/BranchReactActivityLifecycleListener.kt:
--------------------------------------------------------------------------------
1 | package expo.modules.adapters.branch
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.os.Bundle
7 | import expo.modules.core.interfaces.ReactActivityLifecycleListener
8 | import io.branch.rnbranch.RNBranchModule
9 |
10 |
11 | class BranchReactActivityLifecycleListener(activityContext: Context) : ReactActivityLifecycleListener {
12 | override fun onCreate(activity: Activity, savedInstanceState: Bundle?) {
13 | RNBranchModule.initSession(activity.getIntent().getData(), activity);
14 | }
15 |
16 | override fun onNewIntent(intent: Intent?): Boolean {
17 | if (intent != null) {
18 | RNBranchModule.onNewIntent(intent);
19 | }
20 | return super.onNewIntent(intent)
21 | }
22 | }
--------------------------------------------------------------------------------
/packages/react-native-branch/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withBranch");
2 |
--------------------------------------------------------------------------------
/packages/react-native-branch/expo-module.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "platforms": [
3 | "android",
4 | "ios"
5 | ],
6 | "ios": {
7 | "appDelegateSubscribers": ["BranchAppDelegate"]
8 | }
9 | }
--------------------------------------------------------------------------------
/packages/react-native-branch/ios/ExpoAdapterBranch.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'ExpoAdapterBranch'
7 | s.version = package['version']
8 | s.summary = package['description']
9 | s.description = package['description']
10 | s.license = package['license']
11 | s.author = package['author']
12 | s.homepage = package['homepage']
13 | s.platforms = {
14 | :ios => '15.1',
15 | }
16 | s.swift_version = '5.4'
17 | s.source = { git: 'https://github.com/expo/config-plugins.git' }
18 | s.static_framework = true
19 |
20 | s.compiler_flags = %[-DRNBRANCH_VERSION=@\\"#{package.has_key?("dependencies") ? package["dependencies"]["react-native-branch"] || "5.4.0" : "5.4.0"}\\"]
21 |
22 | s.dependency 'ExpoModulesCore'
23 | s.dependency 'React-Core'
24 | s.dependency 'react-native-branch'
25 |
26 | # Swift/Objective-C compatibility
27 | s.pod_target_xcconfig = {
28 | 'DEFINES_MODULE' => 'YES'
29 | }
30 |
31 | if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
32 | s.source_files = "#{s.name}/**/*.h"
33 | s.vendored_frameworks = "#{s.name}.xcframework"
34 | else
35 | s.source_files = "**/*.{h,m,swift}"
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/packages/react-native-branch/ios/ExpoAdapterBranch/BranchAppDelegate.swift:
--------------------------------------------------------------------------------
1 | import ExpoModulesCore
2 | import RNBranch
3 |
4 | public class BranchAppDelegate: ExpoAppDelegateSubscriber {
5 | public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
6 | RNBranch.initSession(launchOptions: launchOptions, isReferrable: true)
7 | return true
8 | }
9 |
10 | public func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
11 | return RNBranch.application(application, open:url, options:options)
12 | }
13 |
14 | public func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
15 | return RNBranch.continue(userActivity)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/react-native-branch/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('expo-module-scripts/jest-preset-plugin');
2 |
--------------------------------------------------------------------------------
/packages/react-native-branch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-branch",
3 | "version": "10.0.0",
4 | "description": "Config plugin to auto configure react-native-branch on prebuild",
5 | "author": "650 Industries, Inc.",
6 | "license": "MIT",
7 | "homepage": "https://docs.expo.dev/versions/latest/sdk/branch/",
8 | "main": "build/withBranch.js",
9 | "types": "build/withBranch.d.ts",
10 | "sideEffects": false,
11 | "files": [
12 | "android",
13 | "app.plugin.js",
14 | "build",
15 | "expo-module.config.json",
16 | "ios"
17 | ],
18 | "scripts": {
19 | "build": "expo-module build",
20 | "clean": "expo-module clean",
21 | "lint": "expo-module lint",
22 | "test": "expo-module test",
23 | "prepare": "expo-module prepare",
24 | "prepublishOnly": "expo-module prepublishOnly",
25 | "expo-module": "expo-module"
26 | },
27 | "keywords": [
28 | "expo",
29 | "react-native",
30 | "react-native-branch"
31 | ],
32 | "peerDependencies": {
33 | "expo": "^53"
34 | },
35 | "upstreamPackage": "react-native-branch"
36 | }
37 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/__tests__/fixtures/react-native-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 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/__tests__/withBranchAndroid.test.ts:
--------------------------------------------------------------------------------
1 | import { AndroidConfig } from "expo/config-plugins";
2 | import { resolve } from "path";
3 |
4 | import { getBranchApiKey, setBranchApiKey } from "../withBranchAndroid";
5 |
6 | const { findMetaDataItem, getMainApplication, readAndroidManifestAsync } =
7 | AndroidConfig.Manifest;
8 |
9 | const sampleManifestPath = resolve(
10 | __dirname,
11 | "./fixtures",
12 | "react-native-AndroidManifest.xml",
13 | );
14 |
15 | describe(getBranchApiKey, () => {
16 | it(`returns null if no android branch api key is provided`, () => {
17 | expect(getBranchApiKey({ android: { config: {} } } as any)).toBe(null);
18 | });
19 |
20 | it(`returns apikey if android branch api key is provided`, () => {
21 | expect(
22 | getBranchApiKey({
23 | android: { config: { branch: { apiKey: "MY-API-KEY" } } },
24 | } as any),
25 | ).toBe("MY-API-KEY");
26 | });
27 | });
28 |
29 | describe(setBranchApiKey, () => {
30 | it("sets branch api key in AndroidManifest.xml if given", async () => {
31 | let androidManifestJson =
32 | await readAndroidManifestAsync(sampleManifestPath);
33 | androidManifestJson = await setBranchApiKey(
34 | "MY-API-KEY",
35 | androidManifestJson,
36 | );
37 | let mainApplication = getMainApplication(androidManifestJson);
38 |
39 | expect(
40 | findMetaDataItem(mainApplication, "io.branch.sdk.BranchKey"),
41 | ).toBeGreaterThan(-1);
42 |
43 | // Unset the item
44 |
45 | androidManifestJson = await setBranchApiKey(null, androidManifestJson);
46 | mainApplication = getMainApplication(androidManifestJson);
47 |
48 | expect(findMetaDataItem(mainApplication, "io.branch.sdk.BranchKey")).toBe(
49 | -1,
50 | );
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/__tests__/withBranchIOS.test.ts:
--------------------------------------------------------------------------------
1 | import { getBranchApiKey, setBranchApiKey } from "../withBranchIOS";
2 |
3 | describe(getBranchApiKey, () => {
4 | it(`returns null if no api key is provided`, () => {
5 | expect(getBranchApiKey({})).toBe(null);
6 | });
7 |
8 | it(`returns the api key if provided`, () => {
9 | expect(
10 | getBranchApiKey({ ios: { config: { branch: { apiKey: "123" } } } }),
11 | ).toBe("123");
12 | });
13 | });
14 |
15 | describe(setBranchApiKey, () => {
16 | it(`sets branch_key.live if the api key is given`, () => {
17 | expect(setBranchApiKey("123", {})).toMatchObject({
18 | branch_key: {
19 | live: "123",
20 | },
21 | });
22 | });
23 |
24 | it(`makes no changes to the infoPlist no api key is provided`, () => {
25 | expect(setBranchApiKey(null, {})).toMatchObject({});
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/types.ts:
--------------------------------------------------------------------------------
1 | export type ConfigData = {
2 | apiKey?: string;
3 | iosAppDomain?: string;
4 | iosUniversalLinkDomains?: string[];
5 | };
6 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/withBranch.ts:
--------------------------------------------------------------------------------
1 | import { ConfigPlugin, createRunOncePlugin } from "expo/config-plugins";
2 |
3 | import { ConfigData } from "./types";
4 | import { withBranchAndroid } from "./withBranchAndroid";
5 | import { withBranchIOS } from "./withBranchIOS";
6 |
7 | const withBranch: ConfigPlugin = (
8 | config,
9 | { apiKey, iosAppDomain, iosUniversalLinkDomains } = {},
10 | ) => {
11 | config = withBranchAndroid(config, { apiKey });
12 | config = withBranchIOS(config, {
13 | apiKey,
14 | iosAppDomain,
15 | iosUniversalLinkDomains,
16 | });
17 | return config;
18 | };
19 |
20 | let pkg: { name: string; version?: string } = {
21 | name: "react-native-branch",
22 | };
23 | try {
24 | const branchPkg = require("react-native-branch/package.json");
25 | pkg = branchPkg;
26 | } catch {}
27 |
28 | export default createRunOncePlugin(withBranch, pkg.name, pkg.version);
29 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/withBranchAndroid.ts:
--------------------------------------------------------------------------------
1 | import { ExpoConfig } from "expo/config";
2 | import {
3 | AndroidConfig,
4 | ConfigPlugin,
5 | withAndroidManifest,
6 | } from "expo/config-plugins";
7 |
8 | const {
9 | addMetaDataItemToMainApplication,
10 | getMainApplicationOrThrow,
11 | removeMetaDataItemFromMainApplication,
12 | } = AndroidConfig.Manifest;
13 |
14 | const META_BRANCH_KEY = "io.branch.sdk.BranchKey";
15 |
16 | export function getBranchApiKey(config: ExpoConfig) {
17 | return config.android?.config?.branch?.apiKey ?? null;
18 | }
19 |
20 | export function setBranchApiKey(
21 | apiKey: string,
22 | androidManifest: AndroidConfig.Manifest.AndroidManifest,
23 | ) {
24 | const mainApplication = getMainApplicationOrThrow(androidManifest);
25 |
26 | if (apiKey) {
27 | // If the item exists, add it back
28 | addMetaDataItemToMainApplication(mainApplication, META_BRANCH_KEY, apiKey);
29 | } else {
30 | // Remove any existing item
31 | removeMetaDataItemFromMainApplication(mainApplication, META_BRANCH_KEY);
32 | }
33 |
34 | return androidManifest;
35 | }
36 |
37 | export const withBranchAndroid: ConfigPlugin<{ apiKey?: string }> = (
38 | config,
39 | data,
40 | ) => {
41 | const apiKey = data.apiKey ?? getBranchApiKey(config);
42 | if (!apiKey) {
43 | throw new Error(
44 | "Branch API key is required: expo.android.config.branch.apiKey",
45 | );
46 | }
47 |
48 | config = withAndroidManifest(config, (config) => {
49 | config.modResults = setBranchApiKey(apiKey, config.modResults);
50 | return config;
51 | });
52 |
53 | return config;
54 | };
55 |
--------------------------------------------------------------------------------
/packages/react-native-branch/src/withBranchIOS.ts:
--------------------------------------------------------------------------------
1 | import { type ExpoConfig } from "expo/config";
2 | import {
3 | type ConfigPlugin,
4 | InfoPlist,
5 | withInfoPlist,
6 | } from "expo/config-plugins";
7 |
8 | import { ConfigData } from "./types";
9 |
10 | export function getBranchApiKey(config: Pick) {
11 | return config.ios?.config?.branch?.apiKey ?? null;
12 | }
13 |
14 | export function setBranchApiKey(
15 | apiKey: string | null,
16 | infoPlist: InfoPlist,
17 | ): InfoPlist {
18 | if (apiKey === null) {
19 | return infoPlist;
20 | }
21 |
22 | return {
23 | ...infoPlist,
24 | branch_key: {
25 | live: apiKey,
26 | },
27 | };
28 | }
29 |
30 | export const withBranchIOS: ConfigPlugin = (config, data) => {
31 | // Ensure object exist
32 | if (!config.ios) {
33 | config.ios = {};
34 | }
35 |
36 | const apiKey = data.apiKey ?? getBranchApiKey(config);
37 | if (!apiKey) {
38 | throw new Error(
39 | "Branch API key is required: expo.ios.config.branch.apiKey",
40 | );
41 | }
42 |
43 | // Update the infoPlist with the branch key and branch domain
44 | config = withInfoPlist(config, (config) => {
45 | config.modResults = setBranchApiKey(apiKey, config.modResults);
46 | if (data.iosAppDomain) {
47 | config.modResults.branch_app_domain = data.iosAppDomain;
48 | } else {
49 | delete config.modResults.branch_app_domain;
50 | }
51 | if (data.iosUniversalLinkDomains) {
52 | config.modResults.branch_universal_link_domains =
53 | data.iosUniversalLinkDomains;
54 | } else {
55 | delete config.modResults.branch_universal_link_domains;
56 | }
57 | return config;
58 | });
59 |
60 | return config;
61 | };
62 |
--------------------------------------------------------------------------------
/packages/react-native-branch/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "build",
5 | "rootDir": "src"
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-callkeep 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ## @config-plugins/react-native-callkeep [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-callkeep@1.0.3...@config-plugins/react-native-callkeep@2.0.0) (2022-07-25)
6 |
7 | ### ⚠ BREAKING CHANGES
8 |
9 | - add SDK 45 support (#79)
10 |
11 | ### Features
12 |
13 | - add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
14 |
15 | ### Other chores
16 |
17 | - publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
18 |
19 | ### @config-plugins/react-native-callkeep [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-callkeep@1.0.2...@config-plugins/react-native-callkeep@1.0.3) (2022-03-22)
20 |
21 | ### Other chores
22 |
23 | - **react-native-callkeep:** lint fix ([241d378](https://github.com/expo/config-plugins/commit/241d378a54327340df3663ef8f66cb8663e1e359))
24 |
25 | ### @config-plugins/react-native-callkeep [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-callkeep@1.0.1...@config-plugins/react-native-callkeep@1.0.2) (2022-03-22)
26 |
27 | ### Other chores
28 |
29 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
30 |
31 | ### @config-plugins/react-native-callkeep [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-callkeep@1.0.0...@config-plugins/react-native-callkeep@1.0.1) (2022-03-16)
32 |
33 | ### Continuous Integration
34 |
35 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
36 |
37 | ## @config-plugins/react-native-callkeep 1.0.0 (2022-03-15)
38 |
39 | ### Other chores
40 |
41 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
42 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/README.md:
--------------------------------------------------------------------------------
1 | # config-plugins/react-native-callkeep
2 |
3 | Config plugin to auto-configure `react-native-callkeep` when the native code is generated (`npx expo prebuild`).
4 |
5 | ## Versioning
6 |
7 | Ensure you use versions that work together!
8 |
9 | | `expo` | `react-native-callkeep` | `@config-plugins/react-native-callkeep` |
10 | | ------ | ----------------------- | --------------------------------------- |
11 | | 53.0.0 | 4.3.16 | 10.0.0 |
12 | | 52.0.0 | 4.3.16 | 9.0.0 |
13 | | 51.0.0 | 4.3.13 | 8.0.0 |
14 | | 50.0.0 | 4.3.12 | 7.0.0 |
15 | | 49.0.0 | 4.3.9 | 6.0.0 |
16 | | 48.0.0 | 4.3.7 | 5.0.0 |
17 |
18 | ### Add the package to your npm dependencies
19 |
20 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
21 |
22 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
23 |
24 | ```
25 | npx expo install react-native-callkeep @config-plugins/react-native-callkeep
26 | ```
27 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withCallkeep");
2 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('expo-module-scripts/jest-preset-plugin');
2 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-callkeep",
3 | "version": "11.0.0",
4 | "description": "Config plugin to auto configure callkeep on prebuild",
5 | "main": "build/withCallkeep.js",
6 | "types": "build/withCallkeep.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-callkeep"
13 | },
14 | "files": [
15 | "build",
16 | "app.plugin.js"
17 | ],
18 | "scripts": {
19 | "build": "expo-module build",
20 | "clean": "expo-module clean",
21 | "lint": "expo-module lint",
22 | "test": "expo-module test",
23 | "prepare": "expo-module prepare",
24 | "prepublishOnly": "expo-module prepublishOnly",
25 | "expo-module": "expo-module"
26 | },
27 | "keywords": [
28 | "react-native",
29 | "expo"
30 | ],
31 | "peerDependencies": {
32 | "expo": "^53"
33 | },
34 | "upstreamPackage": "react-native-callkeep"
35 | }
36 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/src/ensureHeaderSearchPath.ts:
--------------------------------------------------------------------------------
1 | import { XcodeProject } from "expo/config-plugins";
2 |
3 | const COMMENT_KEY = /_comment$/;
4 |
5 | function unquote(str: string) {
6 | if (str) return str.replace(/^"(.*)"$/, "$1");
7 | }
8 | function nonComments(obj: Record) {
9 | const keys = Object.keys(obj);
10 | const newObj: Record = {};
11 |
12 | for (let i = 0; i < keys.length; i++) {
13 | if (!COMMENT_KEY.test(keys[i])) {
14 | newObj[keys[i]] = obj[keys[i]];
15 | }
16 | }
17 |
18 | return newObj;
19 | }
20 |
21 | export function ensureHeaderSearchPath(project: XcodeProject, file: string) {
22 | const configurations = nonComments(project.pbxXCBuildConfigurationSection());
23 | const INHERITED = '"$(inherited)"';
24 |
25 | for (const config in configurations) {
26 | const buildSettings = configurations[config].buildSettings;
27 |
28 | if (unquote(buildSettings["PRODUCT_NAME"]) !== project.productName)
29 | continue;
30 |
31 | if (!buildSettings["HEADER_SEARCH_PATHS"]) {
32 | buildSettings["HEADER_SEARCH_PATHS"] = [INHERITED];
33 | }
34 |
35 | if (!buildSettings.HEADER_SEARCH_PATHS.includes(file)) {
36 | buildSettings["HEADER_SEARCH_PATHS"].push(file);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/react-native-callkeep/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "build",
5 | "rootDir": "src"
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react-native-dynamic-app-icon/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-dynamic-app-icon/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-dynamic-app-icon 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ## @config-plugins/react-native-dynamic-app-icon [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-dynamic-app-icon@1.0.3...@config-plugins/react-native-dynamic-app-icon@2.0.0) (2022-06-14)
6 |
7 | ### ⚠ BREAKING CHANGES
8 |
9 | - add SDK 45 support (#79)
10 |
11 | ### Features
12 |
13 | - add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
14 |
15 | ### Other chores
16 |
17 | - publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
18 |
19 | ### @config-plugins/react-native-dynamic-app-icon [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-dynamic-app-icon@1.0.2...@config-plugins/react-native-dynamic-app-icon@1.0.3) (2022-05-12)
20 |
21 | ### Other chores
22 |
23 | - **react-native-dynamic-app-icon:** lint fix ([ce1a818](https://github.com/expo/config-plugins/commit/ce1a818564b30ea2adb057d8f64960da52d026ed))
24 |
25 | ### @config-plugins/react-native-dynamic-app-icon [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-dynamic-app-icon@1.0.1...@config-plugins/react-native-dynamic-app-icon@1.0.2) (2022-03-22)
26 |
27 | ### Other chores
28 |
29 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
30 |
31 | ### @config-plugins/react-native-dynamic-app-icon [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-dynamic-app-icon@1.0.0...@config-plugins/react-native-dynamic-app-icon@1.0.1) (2022-03-16)
32 |
33 | ### Continuous Integration
34 |
35 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
36 |
37 | ## @config-plugins/react-native-dynamic-app-icon 1.0.0 (2022-03-15)
38 |
39 | ### Other chores
40 |
41 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
42 |
--------------------------------------------------------------------------------
/packages/react-native-dynamic-app-icon/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/react-native-dynamic-app-icon
2 |
3 | > Consider using [`expo-quick-actions/icon`](https://github.com/evanbacon/expo-quick-actions) instead for both iOS and Android support, along with dark mode support for iOS.
4 |
5 | Config plugin to auto-configure `react-native-dynamic-app-icon` when the native code is generated (`npx expo prebuild`).
6 |
7 | ## Versioning
8 |
9 | Ensure you use versions that work together!
10 |
11 | | `expo` | `react-native-dynamic-app-icon` | `@config-plugins/react-native-dynamic-app-icon` |
12 | | ------ | ------------------------------- | ----------------------------------------------- |
13 | | 53.0.0 | 1.1.0 | 10.0.0 |
14 | | 52.0.0 | 1.1.0 | 9.0.0 |
15 | | 51.0.0 | 1.1.0 | 8.0.0 |
16 | | 50.0.0 | 1.1.0 | 7.0.0 |
17 | | 49.0.0 | 1.1.0 | 6.0.0 |
18 |
19 | ## Install
20 |
21 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
22 |
23 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
24 |
25 | ```
26 | npx expo install react-native-dynamic-app-icon @config-plugins/react-native-dynamic-app-icon
27 | ```
28 |
29 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`. Then rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
30 |
31 | ## Example
32 |
33 | In your app.json `plugins` array:
34 |
35 | ```json
36 | {
37 | "plugins": [
38 | [
39 | "@config-plugins/react-native-dynamic-app-icon",
40 | ["./path/to/image.png", "https://mywebsite.com/my-icon.png"]
41 | ]
42 | ]
43 | }
44 | ```
45 |
46 | Or as objects:
47 |
48 | ```json
49 | {
50 | "plugins": [
51 | [
52 | "@config-plugins/react-native-dynamic-app-icon",
53 | {
54 | "AppIcon1": {
55 | "image": "./path/to/image.png",
56 | "prerendered": true
57 | }
58 | }
59 | ]
60 | ]
61 | }
62 | ```
63 |
64 | > Note: Icon URLs will be downloaded and embedded at build time, you cannot push new icons OTA.
65 |
66 | ## Usage
67 |
68 | In list format, icons are named after the item index (`'0', '1', '2'`), they can be changed like `AppIcon.setAppIcon('2')` (from the package `react-native-dynamic-app-icon`).
69 |
70 | This isn't tied to `react-native-dynamic-app-icon` in any way, so any method of swapping icons works.
71 |
72 |
73 |
--------------------------------------------------------------------------------
/packages/react-native-dynamic-app-icon/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-dynamic-app-icon",
3 | "version": "11.0.0",
4 | "description": "Config plugin to auto configure react-native-dynamic-app-icon",
5 | "main": "build/index.js",
6 | "types": "build/index.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-dynamic-app-icon"
13 | },
14 | "scripts": {
15 | "build": "expo-module build",
16 | "clean": "expo-module clean",
17 | "lint": "expo-module lint",
18 | "test": "expo-module test",
19 | "prepare": "expo-module prepare",
20 | "prepublishOnly": "expo-module prepublishOnly",
21 | "expo-module": "expo-module"
22 | },
23 | "keywords": [
24 | "react",
25 | "expo"
26 | ],
27 | "dependencies": {
28 | "xcode": "^3.0.1"
29 | },
30 | "peerDependencies": {
31 | "expo": "^53"
32 | },
33 | "upstreamPackage": "react-native-dynamic-app-icon"
34 | }
35 |
--------------------------------------------------------------------------------
/packages/react-native-dynamic-app-icon/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "sourceMap": true
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-pdf 5.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ## @config-plugins/react-native-pdf [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-pdf@1.0.2...@config-plugins/react-native-pdf@2.0.0) (2022-08-04)
6 |
7 | ### ⚠ BREAKING CHANGES
8 |
9 | - add SDK 45 support (#79)
10 |
11 | ### Features
12 |
13 | - add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
14 |
15 | ### Other chores
16 |
17 | - publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
18 |
19 | ### @config-plugins/react-native-pdf [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-pdf@1.0.1...@config-plugins/react-native-pdf@1.0.2) (2022-03-22)
20 |
21 | ### Other chores
22 |
23 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
24 |
25 | ### @config-plugins/react-native-pdf [1.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-pdf@1.0.0...@config-plugins/react-native-pdf@1.0.1) (2022-03-16)
26 |
27 | ### Continuous Integration
28 |
29 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
30 |
31 | ## @config-plugins/react-native-pdf 1.0.0 (2022-03-15)
32 |
33 | ### Other chores
34 |
35 | - upgrade @expo/config-plugins ([#49](https://github.com/expo/config-plugins/issues/49)) ([119e31e](https://github.com/expo/config-plugins/commit/119e31edf110409272ace750f02d651124e1a22d))
36 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/README.md:
--------------------------------------------------------------------------------
1 | # config-plugins/react-native-pdf
2 |
3 | > Consider using a WebView or WebBrowser to quickly display a PDF in your app. Read the alternatives section to learn more.
4 |
5 | Config plugin to auto-configure [`react-native-pdf`][lib] when the native code is generated (`npx expo prebuild`).
6 |
7 | ## Versioning
8 |
9 | Ensure you use versions that work together!
10 |
11 | | `expo` | `react-native-pdf` | `@config-plugins/react-native-pdf` |
12 | | ------ | ------------------ | ---------------------------------- |
13 | | 53.0.0 | 6.7.7 | 10.0.0 |
14 | | 52.0.0 | 6.7.6 | 9.0.0 |
15 | | 51.0.0 | 6.7.5 | 8.0.0 |
16 | | 50.0.0 | 6.7.4 | 7.0.0 |
17 | | 49.0.0 | 6.7.1 | 6.0.0 |
18 | | 48.0.0 | 6.6.2 | 5.0.0 |
19 |
20 | ### Add the package to your npm dependencies
21 |
22 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
23 |
24 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
25 |
26 | ```
27 | npx expo install react-native-pdf react-native-blob-util @config-plugins/react-native-pdf @config-plugins/react-native-blob-util
28 | ```
29 |
30 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
31 |
32 | ```json
33 | {
34 | "plugins": [
35 | "@config-plugins/react-native-blob-util",
36 | "@config-plugins/react-native-pdf"
37 | ]
38 | }
39 | ```
40 |
41 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
42 |
43 | [lib]: https://www.npmjs.com/package/react-native-pdf
44 |
45 | ### Alternatives
46 |
47 | Consider opening a WebBrowser to display a PDF:
48 |
49 | ```js
50 | import * as WebBrowser from "expo-web-browser";
51 | import { Text } from "react-native";
52 |
53 | export default function HomeScreen() {
54 | return (
55 | {
57 | WebBrowser.openBrowserAsync(
58 | "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
59 | );
60 | }}
61 | >
62 | Open in-app browser
63 |
64 | );
65 | }
66 | ```
67 |
68 | Or inside a `WebView` for a contained view:
69 |
70 | ```js
71 | import { WebView } from "react-native-webview";
72 |
73 | export default function HomeScreen() {
74 | return (
75 |
81 | );
82 | }
83 | ```
84 |
85 | Alternatively, if users have a favorite PDF viewer app than consider using `Share` API to let users open the PDF in their preferred app. This is akin to how `UIDocumentInteractionController` is intended to be used on iOS.
86 |
87 | Finally, you could use [DOM Components](https://docs.expo.dev/guides/dom-components/) for a custom web experience.
88 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withPdf");
2 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('expo-module-scripts/jest-preset-plugin');
2 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-pdf",
3 | "version": "11.0.0",
4 | "description": "Config plugin to auto configure react-native-pdf on prebuild",
5 | "main": "build/withPdf.js",
6 | "types": "build/withPdf.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-pdf"
13 | },
14 | "files": [
15 | "build",
16 | "app.plugin.js"
17 | ],
18 | "scripts": {
19 | "build": "expo-module build",
20 | "clean": "expo-module clean",
21 | "lint": "expo-module lint",
22 | "test": "expo-module test",
23 | "prepare": "expo-module prepare",
24 | "prepublishOnly": "expo-module prepublishOnly",
25 | "expo-module": "expo-module"
26 | },
27 | "keywords": [
28 | "react-native-pdf",
29 | "react-native",
30 | "expo"
31 | ],
32 | "peerDependencies": {
33 | "expo": "^53"
34 | },
35 | "upstreamPackage": "react-native-pdf"
36 | }
37 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/src/__tests__/__snapshots__/withPdf.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`addAndroidPackagingOptions adds packaging options to the app build.gradle 1`] = `
4 | "
5 | android {
6 | // @generated begin react-native-pdf-packaging-options - expo prebuild (DO NOT MODIFY) sync-e288c3c5efbb1ef5e1a1959a848260c36558a381
7 |
8 | packagingOptions {
9 | pickFirst 'lib/x86/libc++_shared.so'
10 | pickFirst 'lib/x86_64/libjsc.so'
11 | pickFirst 'lib/arm64-v8a/libjsc.so'
12 | pickFirst 'lib/arm64-v8a/libc++_shared.so'
13 | pickFirst 'lib/x86_64/libc++_shared.so'
14 | pickFirst 'lib/armeabi-v7a/libc++_shared.so'
15 | }
16 |
17 | // @generated end react-native-pdf-packaging-options
18 | defaultConfig {
19 | applicationId 'com.example.app'
20 | }
21 | }
22 | "
23 | `;
24 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/src/__tests__/withPdf.test.ts:
--------------------------------------------------------------------------------
1 | import { addAndroidPackagingOptions } from "../withPdf";
2 |
3 | describe(addAndroidPackagingOptions, () => {
4 | it(`adds packaging options to the app build.gradle`, () => {
5 | const result = addAndroidPackagingOptions(`
6 | android {
7 | defaultConfig {
8 | applicationId 'com.example.app'
9 | }
10 | }
11 | `);
12 | expect(result.contents).toMatchSnapshot();
13 | expect(result.didMerge).toBe(true);
14 | expect(result.didClear).toBe(false);
15 |
16 | const secondResults = addAndroidPackagingOptions(result.contents);
17 |
18 | expect(secondResults.contents).toBe(result.contents);
19 | expect(secondResults.didMerge).toBe(false);
20 | expect(secondResults.didClear).toBe(false);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/src/withPdf.ts:
--------------------------------------------------------------------------------
1 | import { mergeContents } from "@expo/config-plugins/build/utils/generateCode";
2 | import {
3 | ConfigPlugin,
4 | createRunOncePlugin,
5 | WarningAggregator,
6 | withAppBuildGradle,
7 | } from "expo/config-plugins";
8 |
9 | let pkg: { name: string; version?: string } = {
10 | name: "react-native-pdf",
11 | };
12 | try {
13 | pkg = require("react-native-pdf/package.json");
14 | } catch {
15 | // empty catch block
16 | }
17 |
18 | export const withAndroidPackagingOptions: ConfigPlugin = (config) => {
19 | return withAppBuildGradle(config, (config) => {
20 | if (config.modResults.language === "groovy") {
21 | config.modResults.contents = addAndroidPackagingOptions(
22 | config.modResults.contents,
23 | ).contents;
24 | } else {
25 | WarningAggregator.addWarningAndroid(
26 | "@config-plugins/react-native-pdf",
27 | `Cannot automatically configure app build.gradle if it's not groovy`,
28 | );
29 | }
30 | return config;
31 | });
32 | };
33 |
34 | export function addAndroidPackagingOptions(src: string) {
35 | return mergeContents({
36 | tag: "react-native-pdf-packaging-options",
37 | src,
38 | newSrc: packagingOptionsContents,
39 | anchor: /android(?:\s+)?\{/,
40 | // Inside the android block.
41 | offset: 1,
42 | comment: "//",
43 | });
44 | }
45 |
46 | const packagingOptionsContents = `
47 | packagingOptions {
48 | pickFirst 'lib/x86/libc++_shared.so'
49 | pickFirst 'lib/x86_64/libjsc.so'
50 | pickFirst 'lib/arm64-v8a/libjsc.so'
51 | pickFirst 'lib/arm64-v8a/libc++_shared.so'
52 | pickFirst 'lib/x86_64/libc++_shared.so'
53 | pickFirst 'lib/armeabi-v7a/libc++_shared.so'
54 | }
55 | `;
56 |
57 | const withReactNativePdf: ConfigPlugin = (config) => {
58 | return withAndroidPackagingOptions(config);
59 | };
60 |
61 | export default createRunOncePlugin(withReactNativePdf, pkg.name, pkg.version);
62 |
--------------------------------------------------------------------------------
/packages/react-native-pdf/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "build",
5 | "rootDir": "src"
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react-native-quick-actions/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/react-native-quick-actions
2 |
3 | > [!IMPORTANT] > `react-native-quick-actions` is archived. Use [`expo-quick-action`](https://github.com/EvanBacon/expo-quick-actions) instead. This config plugin is now deprecated in favor of `expo-quick-action`.
4 |
5 | Expo Config Plugin to auto-configure [`react-native-quick-actions`](https://www.npmjs.com/package/react-native-quick-actions) when the native code is generated (`npx expo prebuild`).
6 |
7 | 
8 |
9 | ## Expo installation
10 |
11 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
12 |
13 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
14 |
15 | ```sh
16 | npx expo install react-native-quick-actions @config-plugins/react-native-quick-actions
17 | ```
18 |
19 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
20 |
21 | ```json
22 | {
23 | "expo": {
24 | "plugins": ["@config-plugins/react-native-quick-actions"]
25 | }
26 | }
27 | ```
28 |
29 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
30 |
31 | ## API
32 |
33 | The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
34 |
35 | iOS only; an array of the objects with the following keys:
36 |
37 | - `title`: (_string_): `UIApplicationShortcutItemTitle`: Name of action (required)
38 | - `type`: (_string_): `UIApplicationShortcutItemType`: A unique string that the system passes to your app (required)
39 | - `subtitle` (_string_): `UIApplicationShortcutItemSubtitle`: Subtitle message
40 | - `iconType` (_string_): `UIApplicationShortcutItemIconType`: List of [icon types](https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-images/system-icons/#home-screen-quick-action-icons) (ex: "UIApplicationShortcutIconTypeLocation")
41 | - `iconSymbolName` (_string_): `UIApplicationShortcutItemIconSymbolName`: Name of system icon, here is an [unofficial list](https://github.com/NathanE73/Blackboard/blob/576bd088a21a5c8f4f441d4b1da2366b8e9658dc/README/SymbolAvailability.md#symbol-availability) (ex: "square.stack.3d.up")
42 | - `iconFile` (_string_): `UIApplicationShortcutItemIconFile`: Name of the resource file (Not supported)
43 | - `userInfo` (_XML.XMLObject_): `UIApplicationShortcutItemUserInfo`: An optional, app-defined dictionary. One use for this dictionary is to provide app version information, as described in the “App Launch and App Update Considerations for Quick Actions” section of the overview in UIApplicationShortcutItem Class Reference.
44 |
45 | #### Example
46 |
47 | ```json
48 | {
49 | "expo": {
50 | "plugins": [
51 | [
52 | "@config-plugins/react-native-quick-actions",
53 | [
54 | {
55 | "title": "Take Photo",
56 | "type": "photo",
57 | "iconType": "UIApplicationShortcutIconTypeCapturePhoto"
58 | }
59 | ]
60 | ]
61 | ]
62 | }
63 | }
64 | ```
65 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-siri-shortcut 4.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ## @config-plugins/react-native-siri-shortcut 1.0.0 (2022-07-12)
6 |
7 | ### Features
8 |
9 | - **siri-shortcut:** Add config plugin ([#86](https://github.com/expo/config-plugins/issues/86)) ([226b2a6](https://github.com/expo/config-plugins/commit/226b2a6412ad3fe75c98952831fab5a63254d19f))
10 |
11 | ### Other chores
12 |
13 | - **react-native-siri-shortcut:** add tests ([#88](https://github.com/expo/config-plugins/issues/88)) ([994fadc](https://github.com/expo/config-plugins/commit/994fadc8ddf9ee858f2ccb7d544674f107f7f9ad))
14 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/react-native-siri-shortcut
2 |
3 | Expo Config Plugin to auto-configure [`react-native-siri-shortcut`](https://www.npmjs.com/package/react-native-siri-shortcut) when the native code is generated (`npx expo prebuild`).
4 |
5 | ## Versioning
6 |
7 | Ensure you use versions that work together!
8 |
9 | | `expo` | `react-native-siri-shortcut` | `@config-plugins/react-native-siri-shortcut` |
10 | | ------ | ---------------------------- | -------------------------------------------- |
11 | | 53.0.0 | 3.2.4 | 9.0.0 |
12 | | 52.0.0 | 3.2.4 | 8.0.0 |
13 | | 51.0.0 | 3.2.4 | 7.0.0 |
14 | | 50.0.0 | 3.2.4 | 6.0.0 |
15 | | 49.0.0 | 3.2.3 | 5.0.0 |
16 | | 48.0.0 | 3.2.2 | 4.0.0 |
17 |
18 | ## Expo installation
19 |
20 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
21 |
22 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
23 |
24 | ```sh
25 | npx expo install react-native-siri-shortcut @config-plugins/react-native-siri-shortcut
26 | ```
27 |
28 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
29 |
30 | ```json
31 | {
32 | "plugins": ["@config-plugins/react-native-siri-shortcut"]
33 | }
34 | ```
35 |
36 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
37 |
38 | ## API
39 |
40 | When working with Siri Shorcuts, you need to define their identifiers on the Xcode project. To achieve the same result using this plugin, just pass an array of strings with the identifiers of your shortcuts, and they will be added automatically during the build cycle:
41 |
42 | #### Example
43 |
44 | ```json
45 | {
46 | "plugins": [
47 | [
48 | "@config-plugins/react-native-siri-shortcut",
49 | ["com.example.InitiateWorkout", "com.example.FinishWorkout"]
50 | ]
51 | ]
52 | }
53 | ```
54 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withReactNativeSiriShortcut");
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('expo-module-scripts/jest-preset-plugin');
2 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-siri-shortcut",
3 | "version": "10.0.0",
4 | "description": "Config plugin for react-native-siri-shortcut package",
5 | "main": "build/withReactNativeSiriShortcut.js",
6 | "types": "build/withReactNativeSiriShortcut.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-siri-shortcut"
13 | },
14 | "scripts": {
15 | "build": "expo-module build",
16 | "clean": "expo-module clean",
17 | "lint": "expo-module lint",
18 | "test": "expo-module test",
19 | "prepare": "expo-module prepare",
20 | "prepublishOnly": "expo-module prepublishOnly",
21 | "expo-module": "expo-module"
22 | },
23 | "keywords": [
24 | "react",
25 | "expo",
26 | "config-plugins",
27 | "prebuild",
28 | "react-native-siri-shortcut"
29 | ],
30 | "dependencies": {
31 | "glob": "^10.4.2"
32 | },
33 | "peerDependencies": {
34 | "expo": "^53"
35 | },
36 | "upstreamPackage": "react-native-siri-shortcut"
37 | }
38 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/src/__tests__/withReactNativeSiriShortcut.test.ts:
--------------------------------------------------------------------------------
1 | import { getFixture } from "../../../../fixtures/getFixtures";
2 | import {
3 | addSiriShortcutAppDelegateImport,
4 | addSiriShortcutAppDelegateInit,
5 | addSiriShortcutBridgingHeaderImport,
6 | } from "../withReactNativeSiriShortcut";
7 |
8 | const BridgingHeader = getFixture("app-Bridging-Header.h");
9 | const ExpoModulesAppDelegate = getFixture("AppDelegate.mm");
10 | const ExpoModulesSwiftAppDelegate = getFixture("AppDelegate.swift");
11 |
12 | describe(addSiriShortcutBridgingHeaderImport, () => {
13 | it(`adds import to swift Expo Modules AppDelegate`, () => {
14 | const results = addSiriShortcutBridgingHeaderImport(BridgingHeader);
15 | // matches a static snapshot
16 | expect(results.contents).toMatchSnapshot();
17 | expect(results.contents).toMatch(/react-native-siri-shortcut/);
18 | expect(results.contents).toMatch(/RNSiriShortcuts\/RNSiriShortcuts\.h/);
19 | // did add new content
20 | expect(results.didMerge).toBe(true);
21 | // didn't remove old content
22 | expect(results.didClear).toBe(false);
23 | });
24 | });
25 |
26 | describe(addSiriShortcutAppDelegateImport, () => {
27 | it(`adds import to swift Expo Modules AppDelegate`, () => {
28 | expect(
29 | addSiriShortcutAppDelegateImport(ExpoModulesSwiftAppDelegate, "swift"),
30 | ).toBe(null);
31 | });
32 |
33 | it(`adds import to objcpp Expo Modules AppDelegate`, () => {
34 | const results = addSiriShortcutAppDelegateImport(
35 | ExpoModulesAppDelegate,
36 | "objcpp",
37 | )!;
38 | // matches a static snapshot
39 | expect(results.contents).toMatchSnapshot();
40 | expect(results.contents).toMatch(/react-native-siri-shortcut/);
41 | expect(results.contents).toMatch(/RNSiriShortcuts\/RNSiriShortcuts\.h/);
42 | // did add new content
43 | expect(results.didMerge).toBe(true);
44 | // didn't remove old content
45 | expect(results.didClear).toBe(false);
46 | });
47 |
48 | it(`fails to add to a malformed app delegate`, () => {
49 | expect(() => addSiriShortcutAppDelegateImport(`foobar`, "objcpp")).toThrow(
50 | /foobar/,
51 | );
52 | });
53 | });
54 | describe(addSiriShortcutAppDelegateInit, () => {
55 | it(`adds init to swift Expo Modules AppDelegate`, () => {
56 | const results = addSiriShortcutAppDelegateInit(
57 | ExpoModulesSwiftAppDelegate,
58 | "swift",
59 | );
60 | // matches a static snapshot
61 | expect(results.contents).toMatchSnapshot();
62 | expect(results.contents).toMatch(/react-native-siri-shortcut-delegate/);
63 |
64 | // did add new content
65 | expect(results.didMerge).toBe(true);
66 | // didn't remove old content
67 | expect(results.didClear).toBe(false);
68 | });
69 | it(`adds init to objcpp Expo Modules AppDelegate`, () => {
70 | const results = addSiriShortcutAppDelegateInit(
71 | ExpoModulesAppDelegate,
72 | "objcpp",
73 | );
74 | // matches a static snapshot
75 | expect(results.contents).toMatchSnapshot();
76 | expect(results.contents).toMatch(/react-native-siri-shortcut-delegate/);
77 | expect(results.contents).toMatch(
78 | /RNSSSiriShortcuts application:application/,
79 | );
80 | // did add new content
81 | expect(results.didMerge).toBe(true);
82 | // didn't remove old content
83 | expect(results.didClear).toBe(false);
84 | });
85 |
86 | it(`fails to add to a malformed app delegate`, () => {
87 | expect(() => addSiriShortcutAppDelegateInit(`foobar`, "objcpp")).toThrow(
88 | /foobar/,
89 | );
90 | });
91 | });
92 |
--------------------------------------------------------------------------------
/packages/react-native-siri-shortcut/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "./build"
5 | },
6 | "include": ["./src"],
7 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @generated by expo-module-scripts
2 | module.exports = require('expo-module-scripts/eslintrc.base.js');
3 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### @config-plugins/react-native-webrtc 6.0.0
2 |
3 | - Expo SDK 48 support
4 |
5 | ### @config-plugins/react-native-webrtc [2.1.1](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-webrtc@2.1.0...@config-plugins/react-native-webrtc@2.1.1) (2022-03-22)
6 |
7 | ### Other chores
8 |
9 | - git ignore build folders ([#59](https://github.com/expo/config-plugins/issues/59)) ([d6050be](https://github.com/expo/config-plugins/commit/d6050beb2a5c68dc59287c27ec388c2002ec7904))
10 |
11 | ## @config-plugins/react-native-webrtc [2.1.0](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-webrtc@2.0.2...@config-plugins/react-native-webrtc@2.1.0) (2022-03-22)
12 |
13 | ### Features
14 |
15 | - **react-native-webrtc:** add config mod for Android minSdkVersion 24 ([ff8b167](https://github.com/expo/config-plugins/commit/ff8b1677640a560ca98abd8a83f349b3a1ee9017))
16 |
17 | ### @config-plugins/react-native-webrtc [2.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/react-native-webrtc@2.0.1...@config-plugins/react-native-webrtc@2.0.2) (2022-03-16)
18 |
19 | ### Continuous Integration
20 |
21 | - fix versions [skip ci] ([#53](https://github.com/expo/config-plugins/issues/53)) ([5de4ae3](https://github.com/expo/config-plugins/commit/5de4ae3e6182c32b7aa24d70ccd23a11663bb089))
22 |
23 | ## @config-plugins/react-native-webrtc 2.0.1
24 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./build/withWebRTC");
2 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('expo-module-scripts/jest-preset-plugin');
2 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/react-native-webrtc",
3 | "version": "12.0.0",
4 | "description": "Config plugin to setup react-native-webrtc on prebuild",
5 | "main": "build/withWebRTC.js",
6 | "types": "build/withWebRTC.d.ts",
7 | "sideEffects": false,
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/expo/config-plugins.git",
12 | "directory": "packages/react-native-webrtc"
13 | },
14 | "files": [
15 | "build",
16 | "app.plugin.js"
17 | ],
18 | "scripts": {
19 | "build": "expo-module build",
20 | "clean": "expo-module clean",
21 | "lint": "expo-module lint",
22 | "test": "expo-module test",
23 | "prepare": "expo-module prepare",
24 | "prepublishOnly": "expo-module prepublishOnly",
25 | "expo-module": "expo-module"
26 | },
27 | "keywords": [
28 | "react-native",
29 | "expo"
30 | ],
31 | "peerDependencies": {
32 | "expo": "^53"
33 | },
34 | "upstreamPackage": "react-native-webrtc"
35 | }
36 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/src/withBitcodeDisabled.ts:
--------------------------------------------------------------------------------
1 | import { type ConfigPlugin, WarningAggregator } from "expo/config-plugins";
2 |
3 | export const withBitcodeDisabled: ConfigPlugin = (config) => {
4 | if (!config.ios) {
5 | config.ios = {};
6 | }
7 |
8 | if (config.ios?.bitcode != null && config.ios?.bitcode !== false) {
9 | WarningAggregator.addWarningIOS(
10 | "ios.bitcode",
11 | "react-native-webrtc plugin is overwriting project bitcode settings. WebRTC requires bitcode to be disabled for builds, targeting physical iOS devices.",
12 | );
13 | }
14 | // WebRTC requires Bitcode be disabled for
15 | // production AND development iOS builds that target devices, e.g. not simulators.
16 | // SDK +44 property
17 | config.ios.bitcode = false;
18 | return config;
19 | };
20 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/src/withPermissions.ts:
--------------------------------------------------------------------------------
1 | import { type ConfigPlugin, withInfoPlist } from "expo/config-plugins";
2 |
3 | const CAMERA_USAGE = "Allow $(PRODUCT_NAME) to access your camera";
4 | const MICROPHONE_USAGE = "Allow $(PRODUCT_NAME) to access your microphone";
5 |
6 | export type IOSPermissionsProps = {
7 | cameraPermission?: string;
8 | microphonePermission?: string;
9 | };
10 |
11 | export const withPermissions: ConfigPlugin = (
12 | config,
13 | props,
14 | ) => {
15 | return withInfoPlist(config, (config) => {
16 | const { cameraPermission, microphonePermission } = props || {};
17 |
18 | config.modResults.NSCameraUsageDescription =
19 | cameraPermission ||
20 | config.modResults.NSCameraUsageDescription ||
21 | CAMERA_USAGE;
22 |
23 | config.modResults.NSMicrophoneUsageDescription =
24 | microphonePermission ||
25 | config.modResults.NSMicrophoneUsageDescription ||
26 | MICROPHONE_USAGE;
27 |
28 | return config;
29 | });
30 | };
31 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/src/withWebRTC.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AndroidConfig,
3 | ConfigPlugin,
4 | createRunOncePlugin,
5 | } from "expo/config-plugins";
6 |
7 | import { withBitcodeDisabled } from "./withBitcodeDisabled";
8 | import { IOSPermissionsProps, withPermissions } from "./withPermissions";
9 |
10 | const pkg = { name: "react-native-webrtc", version: "UNVERSIONED" }; //require("react-native-webrtc/package.json");
11 |
12 | const withWebRTC: ConfigPlugin = (
13 | config,
14 | props = {},
15 | ) => {
16 | const _props = props || {};
17 |
18 | // iOS
19 | config = withPermissions(config, _props);
20 | config = withBitcodeDisabled(config);
21 |
22 | // Android
23 | // https://github.com/react-native-webrtc/react-native-webrtc/blob/master/Documentation/AndroidInstallation.md#declaring-permissions
24 | config = AndroidConfig.Permissions.withPermissions(config, [
25 | "android.permission.ACCESS_NETWORK_STATE",
26 | "android.permission.CAMERA",
27 | "android.permission.INTERNET",
28 | "android.permission.MODIFY_AUDIO_SETTINGS",
29 | "android.permission.RECORD_AUDIO",
30 | "android.permission.SYSTEM_ALERT_WINDOW",
31 | "android.permission.WAKE_LOCK",
32 |
33 | "android.permission.BLUETOOTH",
34 | ]);
35 |
36 | return config;
37 | };
38 |
39 | export default createRunOncePlugin(withWebRTC, pkg.name, pkg.version);
40 |
--------------------------------------------------------------------------------
/packages/react-native-webrtc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "build",
5 | "rootDir": "src"
6 | },
7 | "include": ["./src"],
8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/tv/README.md:
--------------------------------------------------------------------------------
1 | # `@config-plugins/tv`
2 |
3 | This package has moved to [@react-native-tvos/config-tv](https://github.com/react-native-tvos/config-tv)
4 |
--------------------------------------------------------------------------------
/scripts/template/README.md:
--------------------------------------------------------------------------------
1 | # @config-plugins/%CONFIG_PLUGIN%
2 |
3 | Expo Config Plugin to auto-configure [`%NPM_MODULE%`](https://www.npmjs.com/package/%NPM_MODULE%) when the native code is generated (`npx expo prebuild`).
4 |
5 | ## Versioning
6 |
7 | | `expo` | `%NPM_MODULE%` | `@config-plugins/%CONFIG_PLUGIN%` |
8 | | ----------------- | -------------- | --------------------------------- |
9 | | %SDK_VERSION%.0.0 | 1.0.0 | ^1.0.0 |
10 |
11 | ## Expo installation
12 |
13 | > This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
14 |
15 | First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install).
16 |
17 | ```sh
18 | npx expo install %NPM_MODULE% @config-plugins/%CONFIG_PLUGIN%
19 | ```
20 |
21 | After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
22 |
23 | ```json
24 | {
25 | "expo": {
26 | "plugins": ["@config-plugins/%CONFIG_PLUGIN%"]
27 | }
28 | }
29 | ```
30 |
31 | Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
32 |
33 | ## API
34 |
35 | The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
36 |
37 | - `foobar` (_boolean_): Does XYZ. Default `false`.
38 |
39 | #### Example
40 |
41 | ```json
42 | {
43 | "expo": {
44 | "plugins": [
45 | [
46 | "@config-plugins/%CONFIG_PLUGIN%",
47 | {
48 | // props ...
49 | }
50 | ]
51 | ]
52 | }
53 | }
54 | ```
55 |
--------------------------------------------------------------------------------
/scripts/template/index.ts:
--------------------------------------------------------------------------------
1 | import { ConfigPlugin, createRunOncePlugin } from "expo/config-plugins";
2 |
3 | /**
4 | * Apply %NPM_MODULE% configuration for Expo SDK %SDK_VERSION% projects.
5 | */
6 | const _MODULE_NAME_: ConfigPlugin<{} | void> = (config, _props = {}) => {
7 | // Support passing no props to the plugin.
8 | const props = _props || {};
9 |
10 | // Return the modified config.
11 | return config;
12 | };
13 |
14 | const pkg = {
15 | // Prevent this plugin from being run more than once.
16 | // This pattern enables users to safely migrate off of this
17 | // out-of-tree `@config-plugins/%CONFIG_PLUGIN%` to a future
18 | // upstream plugin in `%NPM_MODULE%`
19 | name: "%NPM_MODULE%",
20 | // Indicates that this plugin is dangerously linked to a module,
21 | // and might not work with the latest version of that module.
22 | version: "UNVERSIONED",
23 | };
24 |
25 | export default createRunOncePlugin(_MODULE_NAME_, pkg.name, pkg.version);
26 |
--------------------------------------------------------------------------------
/scripts/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@config-plugins/template",
3 | "version": "0.0.0",
4 | "description": "Config plugin to auto configure iOS iMessage stickers",
5 | "main": "build/index.js",
6 | "types": "build/index.d.ts",
7 | "sideEffects": false,
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/expo/config-plugins.git",
11 | "directory": "packages/template"
12 | },
13 | "scripts": {
14 | "build": "expo-module build",
15 | "clean": "expo-module clean",
16 | "lint": "expo-module lint",
17 | "test": "expo-module test",
18 | "prepare": "expo-module prepare",
19 | "prepublishOnly": "expo-module prepublishOnly",
20 | "expo-module": "expo-module"
21 | },
22 | "keywords": [
23 | "react",
24 | "expo",
25 | "config-plugins",
26 | "prebuild"
27 | ],
28 | "peerDependencies": {
29 | "expo": "^53"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/scripts/template/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo-module-scripts/tsconfig.plugin",
3 | "compilerOptions": {
4 | "outDir": "./build"
5 | },
6 | "include": ["./src"],
7 | "exclude": ["**/__mocks__/*", "**/__tests__/*"]
8 | }
9 |
--------------------------------------------------------------------------------
/scripts/update-dependabot-config.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ts-node
2 | import * as fs from "fs/promises";
3 | import { sync as globSync } from "glob";
4 | import * as yaml from "js-yaml";
5 | import * as path from "path";
6 |
7 | /**
8 | * @returns a list of file paths for each package in the packages folder, relative to the root.
9 | * @example
10 | * ```
11 | * ['packages/react-native-callkeep', 'packages/react-native-camera', ...]
12 | * ```
13 | */
14 | function getAllPackageJsonFiles(root: string): string[] {
15 | const packageJsonFiles = globSync("packages/*/package.json", {
16 | cwd: root,
17 | });
18 |
19 | return packageJsonFiles.map((pkgJsonFilePath) =>
20 | path.dirname(pkgJsonFilePath)
21 | );
22 | }
23 |
24 | (async () => {
25 | const root = path.join(__dirname, "../");
26 | const filePaths = getAllPackageJsonFiles(root);
27 |
28 | const config: {
29 | version: number;
30 | updates: {
31 | "package-ecosystem": string;
32 | directory: string;
33 | schedule: { interval?: string; time?: string; timezone?: string };
34 | }[];
35 | } = {
36 | version: 2,
37 | updates: [],
38 | };
39 |
40 | for (const filePath of filePaths.sort()) {
41 | config.updates.push({
42 | "package-ecosystem": "npm",
43 | directory: filePath,
44 | // Default for every package is to run at the beginning of every Expo work day.
45 | schedule: {
46 | interval: "daily",
47 | time: "09:00",
48 | // Expo is based out of California
49 | timezone: "America/Los_Angeles",
50 | },
51 | });
52 | }
53 |
54 | const outputFilePath = path.join(root, ".github/dependabot.yml");
55 |
56 | const results = yaml.dump(config);
57 |
58 | console.log("Results:\n", results);
59 | console.log("");
60 | console.log("Writing to:", outputFilePath);
61 | await fs.writeFile(
62 | outputFilePath,
63 | [
64 | "# AUTO GENERATED:",
65 | "# This file was generated by running the following in the root directory:",
66 | "#",
67 | "# yarn update-dependabot-config",
68 | "",
69 | results,
70 | ].join("\n")
71 | );
72 | })();
73 |
--------------------------------------------------------------------------------