@webority/mobile-tools 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/lib/prebuild.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,8 @@ npx mobile-tools prebuild --same-env [--platform android|ios]
|
|
|
30
30
|
- Sets `CFBundleDisplayName` in `ios/<name>/Info.plist`.
|
|
31
31
|
- In `project.pbxproj`, sets `PRODUCT_BUNDLE_IDENTIFIER` (suffixed), `MARKETING_VERSION` and `CURRENT_PROJECT_VERSION`. It also sets `ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-<Env>` when that icon set exists.
|
|
32
32
|
- When another environment's icon set exists but this one's does not, prebuild fails, so a build never ships the wrong icon.
|
|
33
|
-
- Copies `<firebasePlistDir>/GoogleService-Info.<Env>.plist` to `ios/<name>/GoogleService-Info.plist`. Without that file for the environment
|
|
33
|
+
- Copies `<firebasePlistDir>/GoogleService-Info.<Env>.plist` to `ios/<name>/GoogleService-Info.plist`. Without that file for the environment it fails when the app depends on `@react-native-firebase/app` (the Crashlytics build phase needs it), and otherwise removes the copy.
|
|
34
|
+
- **Firebase on Android**: an app that depends on `@react-native-firebase/app` fails without `android/app/google-services.json`, whose absence would otherwise stop the Gradle build later with a less direct error.
|
|
34
35
|
- Without `--platform`, it stamps every platform folder the app has.
|
|
35
36
|
- `--same-env` recompiles the environment last compiled, which refreshes the build stamp.
|
|
36
37
|
- Running it twice gives the same native files as running it once. A file whose content did not change is not rewritten.
|
package/lib/prebuild.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{copyFileSync,existsSync,readFileSync,rmSync,writeFileSync}from"node:fs";import path from"node:path";import{applicationId,COMPILED_FILE,ENVIRONMENTS,gradleAppId,lastCompiledEnvironment,loadAppSettings,loadToolsConfig,resolveIosProjectName}from"./config.js";import{capture}from"./exec.js";import{fail,say}from"./output.js";import{findOnPath}from"./platform.js";const eolOf=e=>e.includes("\r\n")?"\r\n":"\n";export const rewriteGradleProperties=(e,t)=>{const o=eolOf(e),n=e.split(o),
|
|
1
|
+
import{copyFileSync,existsSync,readFileSync,rmSync,writeFileSync}from"node:fs";import path from"node:path";import{applicationId,COMPILED_FILE,ENVIRONMENTS,gradleAppId,lastCompiledEnvironment,loadAppSettings,loadToolsConfig,resolveIosProjectName}from"./config.js";import{capture}from"./exec.js";import{fail,say}from"./output.js";import{findOnPath}from"./platform.js";const eolOf=e=>e.includes("\r\n")?"\r\n":"\n";export const rewriteGradleProperties=(e,t)=>{const o=eolOf(e),n=e.split(o),s=new Map(Object.entries(t)),i=n.map(e=>{const t=/^\s*([A-Za-z0-9_.-]+)\s*[=:]/.exec(e);if(t&&s.has(t[1])){const e=t[1],o=s.get(e);return s.delete(e),`${e}=${o}`}return e});if(0===s.size)return i.join(o);const r=[...s].map(([e,t])=>`${e}=${t}`);return i.length>1&&""===i[i.length-1]?i.splice(i.length-1,0,...r):1===i.length&&""===i[0]?i.splice(0,1,...r):i.push(...r),i.join(o)};const pbxValue=e=>/^[A-Za-z0-9._/-]+$/.test(e)?e:`"${e.replace(/"/g,'\\"')}"`;export const rewritePbxproj=(e,t,o={})=>{let n=e;for(const[e,s]of Object.entries(t)){const t=new RegExp(`(\\s)${e} = [^;\\n]*;`,"g");t.test(n)||fail(`${e} not found in project.pbxproj`);const i=o.quote?.includes(e)?`"${s.replace(/"/g,'\\"')}"`:pbxValue(s);n=n.replace(t,(t,o)=>`${o}${e} = ${i};`)}return n};const escapeXml=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");export const rewriteInfoPlistDisplayName=(e,t)=>{const o=/(<key>CFBundleDisplayName<\/key>\s*<string>)[^<]*(<\/string>)/;return o.test(e)||fail("CFBundleDisplayName not found in Info.plist"),e.replace(o,(e,o,n)=>`${o}${escapeXml(t)}${n}`)};export const prebuildOutputs=e=>{const t=[COMPILED_FILE,"android/gradle.properties"];return e&&t.push(`ios/${e}/Info.plist`,`ios/${e}.xcodeproj/project.pbxproj`,`ios/${e}/GoogleService-Info.plist`),t};export const buildCommit=(e,t)=>{const o=findOnPath("git",process.env,process.platform);if(!o)return"nogit";const n=capture({file:o,args:["rev-parse","--short","HEAD"]},e);if(0!==n.status)return"nogit";const s=capture({file:o,args:["status","--porcelain","--",".",...t.map(e=>`:(exclude)${e}`)]},e);return 0!==s.status?fail(`git status failed in ${e}: ${s.stderr.trim()}`):""===s.stdout.trim()?n.stdout.trim():`${n.stdout.trim()}-dirty`};const writeIfChanged=(e,t)=>(!existsSync(e)||readFileSync(e,"utf8")!==t)&&(writeFileSync(e,t,"utf8"),!0),report=(e,t,o)=>{say(`prebuild: ${o?"wrote":"unchanged"} ${path.relative(e,t)}`)};export const usesFirebase=e=>{const t=path.join(e,"package.json");if(!existsSync(t))return!1;const o=JSON.parse(readFileSync(t,"utf8"));return Boolean(o.dependencies?.["@react-native-firebase/app"])};export const stampAndroid=(e,t,o,n)=>{const s=path.join(e,"android","gradle.properties");existsSync(s)||fail(`android/gradle.properties not found in ${e}`),usesFirebase(e)&&!existsSync(path.join(e,"android","app","google-services.json"))&&fail("android/app/google-services.json is missing; the app uses @react-native-firebase, whose Gradle plugin needs it");const i=rewriteGradleProperties(readFileSync(s,"utf8"),{APP_NAME:String(t.APP_NAME),APP_ID:gradleAppId(t.APP_ID,o,n.flavors),VERSION_DISPLAY:String(t.VERSION_DISPLAY),VERSION_INTERNAL:String(t.VERSION_INTERNAL)});report(e,s,writeIfChanged(s,i))};export const stampIos=(e,t,o,n,s)=>{const i=path.join(e,"ios",s),r=path.join(i,"Info.plist"),a=path.join(e,"ios",`${s}.xcodeproj`,"project.pbxproj");for(const t of[r,a])existsSync(t)||fail(`${path.relative(e,t)} not found: check "iosProjectName"`);const p=`AppIcon-${o}`,c=path.join(i,"Images.xcassets"),l=existsSync(path.join(c,`${p}.appiconset`)),d=ENVIRONMENTS.filter(e=>e!==o&&existsSync(path.join(c,`AppIcon-${e}.appiconset`)));!l&&d.length>0&&fail(`ios/${s}/Images.xcassets has AppIcon-${d[0]} but no ${p}: run mobile-tools icons`),report(e,r,writeIfChanged(r,rewriteInfoPlistDisplayName(readFileSync(r,"utf8"),String(t.APP_NAME))));const f={PRODUCT_BUNDLE_IDENTIFIER:applicationId(t.APP_ID,o),MARKETING_VERSION:String(t.VERSION_DISPLAY),CURRENT_PROJECT_VERSION:String(t.VERSION_INTERNAL)};l&&(f.ASSETCATALOG_COMPILER_APPICON_NAME=p),report(e,a,writeIfChanged(a,rewritePbxproj(readFileSync(a,"utf8"),f,{quote:["PRODUCT_BUNDLE_IDENTIFIER"]}))),l||say("prebuild: no AppIcon-<Env> sets, app icon left as the project sets it");const u=path.join(i,"GoogleService-Info.plist"),I=path.join(e,n.firebasePlistDir,`GoogleService-Info.${o}.plist`);if(!existsSync(I)&&usesFirebase(e)&&fail(`${path.relative(e,I)} is missing; the app uses @react-native-firebase, and an iOS build without it reports no crashes`),existsSync(I)){const t=!existsSync(u)||!readFileSync(I).equals(readFileSync(u));t&©FileSync(I,u),report(e,u,t)}else existsSync(u)&&(rmSync(u),say(`prebuild: removed ${path.relative(e,u)}, no ${path.relative(e,I)}`))};export const prebuild=e=>{const{appRoot:t,sameEnv:o,platform:n}=e;o&&e.env&&fail("pass --env or --same-env, not both",2);const s=o?lastCompiledEnvironment(t):e.env;if(!s)return fail("prebuild needs --env <Development|Staging|Production> or --same-env",2);const i=loadToolsConfig(t),r=resolveIosProjectName(t,i),a={...loadAppSettings(t,s),COMMIT:buildCommit(t,prebuildOutputs(r)),BUILD_TIME:(new Date).toISOString()};writeFileSync(path.join(t,COMPILED_FILE),`${JSON.stringify(a,null,2)}\n`,"utf8"),say(`prebuild: wrote ${COMPILED_FILE} (${s}, ${a.COMMIT})`);const p=existsSync(path.join(t,"android"));if(("android"===n||!n&&p)&&stampAndroid(t,a,s,i),"ios"===n||!n&&r){if(!r)return fail(`no ios/ folder in ${t}`);stampIos(t,a,s,i,r)}return a};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/mobile-tools",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Dev-time CLI for Webority React Native apps: one prebuild, a dependency guard, a device-aware run and per-environment launcher icons, the same on Windows and macOS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|