├── app.plugin.js ├── .npmignore ├── .gitignore ├── index.js ├── CHANGELOG.md ├── tsconfig.json ├── package.json ├── src └── index.ts └── README.md /app.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./build'); 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | README.md 2 | CHANGELOG.md 3 | src 4 | *.json 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | package-lock.json 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Empty. Need this to satisfy Expo otherwise it doesn't think this is a plugin. 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## [0.1.3] — 2025-05-05 4 | * Fix for Expo 53 Android. The `ext { }` block no longer exists by default. First check if exists and append empty `ext { }` block if not. 5 | 6 | ## [0.1.2] — 2023-10-10 7 | * Don't convert numeric values to string. 8 | 9 | ## [0.1.1] — 2022-10-25 10 | * Initial release 11 | ## [0.1.0] — 2022-10-24 12 | * Initial release 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "build", 4 | "rootDir": "src", 5 | "declaration": true, 6 | "target": "esnext", 7 | "module": "commonjs", 8 | "lib": ["esnext", "ES6", "DOM"], 9 | "allowJs": false, 10 | "jsx": "react-native", 11 | "sourceMap": true, 12 | "listEmittedFiles": true, 13 | "removeComments": false, 14 | "isolatedModules": false, 15 | "strict": true, 16 | "moduleResolution": "node", 17 | "allowSyntheticDefaultImports": true, 18 | "esModuleInterop": true, 19 | "skipLibCheck": true 20 | }, 21 | "exclude": ["node_modules"], 22 | "include": ["./src"] 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "expo-gradle-ext-vars", 3 | "version": "0.1.3", 4 | "description": "Expo plugin to append custom vars to the root android/build.gradle", 5 | "scripts": { 6 | "build": "yarn run build:expo", 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build:expo": "rimraf build && tsc --build" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+ssh://git@github.com/transistorsoft/expo-gradle-ext-vars.git" 13 | }, 14 | "keywords": [ 15 | "react-native", 16 | "expo", 17 | "ext vars" 18 | ], 19 | "author": "Chris Scott, Transistor Software ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/transistorsoft/transistorsoft/expo-gradle-ext-vars/issues" 23 | }, 24 | "homepage": "https://github.com/transistorsoft/transistorsoft/expo-gradle-ext-vars", 25 | "devDependencies": { 26 | "react-native": "^0.52.0", 27 | "rimraf": "^3.0.2", 28 | "@expo/config-plugins": "^4.1.0", 29 | "typescript": "^4.6.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConfigPlugin, 3 | withPlugins, 4 | withProjectBuildGradle, 5 | withDangerousMod, 6 | WarningAggregator 7 | } from '@expo/config-plugins'; 8 | 9 | import { 10 | mergeContents, 11 | removeContents, 12 | } from "@expo/config-plugins/build/utils/generateCode"; 13 | 14 | const MODULE_NAME = "expo-gradle-ext-vars"; 15 | 16 | const EXT_BLOCK_ANCHOR_RE = /ext\s?.*\{/ 17 | 18 | const androidPlugin: ConfigPlugin> = (config, props) => { 19 | return withProjectBuildGradle(config, ({ modResults, ...subConfig }) => { 20 | if (modResults.language !== 'groovy') { 21 | WarningAggregator.addWarningAndroid( 22 | 'withExpoGradleExtVars', 23 | `Cannot automatically configure project build.gradle if it's not groovy`, 24 | ); 25 | return { modResults, ...subConfig }; 26 | } 27 | 28 | // Does this build.gradle contain the ext {} block? 29 | if (!EXT_BLOCK_ANCHOR_RE.test(modResults.contents)) { 30 | // NO: insert the ext {} block using standard Javascript replace, right above buildscript {} block, like this: 31 | // 32 | // ext { // <--- INSERT ext block here. 33 | // 34 | // } 35 | // 36 | // buildscript { 37 | // . 38 | // . 39 | // . 40 | // } 41 | // 42 | modResults.contents = modResults.contents.replace(/(buildscript)/, "ext {\n}\n\n$1"); 43 | } 44 | 45 | modResults.contents = applyExtVars(modResults.contents, props); 46 | return { modResults, ...subConfig }; 47 | }); 48 | } 49 | 50 | const withExpoGradleExtVars: ConfigPlugin<{} | void> = (config, _props) => { 51 | const props = _props || {}; 52 | 53 | return withPlugins(config, [ 54 | [androidPlugin, new Map(Object.entries(props))], 55 | ]); 56 | }; 57 | 58 | const applyExtVars = (buildGradle: string, props:Map) => { 59 | 60 | const newSrc = []; 61 | 62 | console.log('[ ' + MODULE_NAME + '] applying ext vars to android/build.gradle', props); 63 | for (let [key, value] of props) { 64 | if (typeof(value) === 'boolean' || typeof(value) === 'number') { 65 | newSrc.push(`\t${key} = ${value}`) 66 | } else { 67 | newSrc.push(`\t${key} = "${value}"`) 68 | } 69 | } 70 | 71 | return mergeContents({ 72 | tag: `${MODULE_NAME}`, 73 | src: buildGradle, 74 | newSrc: newSrc.join("\n"), 75 | anchor: EXT_BLOCK_ANCHOR_RE, 76 | offset: 1, 77 | comment: "//", 78 | }).contents; 79 | } 80 | 81 | export default withExpoGradleExtVars 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | expo-gradle-ext-vars 2 | ============================================================================== 3 | 4 | [![](https://dl.dropboxusercontent.com/s/nm4s5ltlug63vv8/logo-150-print.png?dl=1)](https://www.transistorsoft.com) 5 | 6 | By [**Transistor Software**](http://transistorsoft.com), creators of [**React Native Background Geolocation**](http://www.transistorsoft.com/shop/products/react-native-background-geolocation) 7 | 8 | ------------------------------------------------------------------------------ 9 | 10 | A simple *Expo Config Plugin* for appending Android `ext` vars to the `android/build.gradle`. `ext` vars are a common Android method for configuring [project-wide, global configuration properties](https://developer.android.com/studio/build/gradle-tips#configure-project-wide-properties) which can be shared by other plugins in order to avoid dependency conflicts. 11 | 12 | A common usage of `ext` vars is to align *Google* / *AndroidX* dependency version across different plugins using the same dependencies. For example: 13 | 14 | ```gradle 15 | dependencies { 16 | implementation "androidx.appcompat:appcompat:${rootProject.ext.appCompatVersion}" 17 | implementation "com.google.android.gms:play-services-location:${rootProject.ext.playServicesLocationVersion}" 18 | } 19 | ``` 20 | 21 | ## Example Result: `android/build.gradle` 22 | 23 | ```diff 24 | import org.apache.tools.ant.taskdefs.condition.Os 25 | 26 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 27 | 28 | buildscript { 29 | ext { 30 | + // @generated begin expo-gradle-ext-vars - expo prebuild (DO NOT MODIFY) sync-8c85b9ad3863726565f7eff0645ac3f5c56ce733 31 | + googlePlayServicesLocationVersion = "20.0.0" 32 | + appCompatVersion = "1.4.2" 33 | + // @generated end expo-gradle-ext-vars 34 | 35 | buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0' 36 | minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21') 37 | compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31') 38 | targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31') 39 | if (findProperty('android.kotlinVersion')) { 40 | kotlinVersion = findProperty('android.kotlinVersion') 41 | } 42 | frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0' 43 | 44 | if (System.properties['os.arch'] == 'aarch64') { 45 | // For M1 Users we need to use the NDK 24 which added support for aarch64 46 | ndkVersion = '24.0.8215888' 47 | } else { 48 | // Otherwise we default to the side-by-side NDK version from AGP. 49 | ndkVersion = '21.4.7075529' 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | ## Installation 56 | 57 | ```bash 58 | npx expo install expo-gradle-ext-vars 59 | ``` 60 | 61 | ## Usage 62 | 63 | Add the following block to your *Expo* app's __`app.json`__. 64 | 65 | :warning: The variables below are only an example. You should only provide variables as prescribed by some other plugin you're installing. 66 | 67 | ```json 68 | { 69 | "expo": { 70 | "plugins": [ 71 | [ 72 | "expo-gradle-ext-vars", { 73 | "googlePlayServicesLocationVersion": "20.0.0", 74 | "appCompatVersion": "1.4.2" 75 | } 76 | ] 77 | ] 78 | } 79 | ``` 80 | 81 | After adding the plugin, run: 82 | 83 | ```bash 84 | npx expo prebuild 85 | ``` 86 | 87 | --------------------------------------------------------------------------------