diff --git a/app.json b/app.json index 318d2ec..41833f5 100644 --- a/app.json +++ b/app.json @@ -10,7 +10,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "com.beenvoice.app", - "buildNumber": "12", + "buildNumber": "13", "icon": "./assets/beenvoice.icon", "infoPlist": { "ITSAppUsesNonExemptEncryption": false, @@ -94,7 +94,7 @@ } ], [ - "expo-mlkit-ocr", + "./plugins/withExpoMlkitOcrEnv.js", { "iosEngine": "auto" } diff --git a/plugins/withExpoMlkitOcrEnv.js b/plugins/withExpoMlkitOcrEnv.js new file mode 100644 index 0000000..85d03cb --- /dev/null +++ b/plugins/withExpoMlkitOcrEnv.js @@ -0,0 +1,104 @@ +// @ts-check +const { createRunOncePlugin, withDangerousMod } = require("@expo/config-plugins"); +const fs = require("fs"); +const path = require("path"); + +const pkg = require("expo-mlkit-ocr/package.json"); + +const DISABLE_LINE = "ENV['EXPO_MLKIT_OCR_DISABLE_MLKIT'] = '1'"; +const MARKER = "expo-mlkit-ocr: iOS Simulator MLKit handling"; + +function resolveIosEngine(props = {}) { + const raw = props.iosEngine ?? "auto"; + return raw === "auto" || raw === "mlkit" || raw === "vision" ? raw : "auto"; +} + +function stripMarkedBlock(podfile) { + const lines = podfile.split(/\r?\n/); + const next = []; + + for (let i = 0; i < lines.length; i += 1) { + const line = lines[i]; + if (!line.includes(MARKER)) { + next.push(line); + continue; + } + + const markerIndent = (line.match(/^\s*/) ?? [""])[0].length; + while (i + 1 < lines.length) { + i += 1; + const candidate = lines[i]; + const candidateIndent = (candidate.match(/^\s*/) ?? [""])[0].length; + if (candidate.trim() === "end" && candidateIndent <= markerIndent) { + break; + } + } + } + + return next.join("\n"); +} + +function stripOrphanedMlkitArchPatch(podfile) { + return podfile + .replace( + /\n\s*end\s*\n\s*\n\s*installer\.aggregate_targets\.each do \|aggregate_target\|[\s\S]*?aggregate_target\.user_project\.save\s*\n\s*end\s*\n/g, + "\n", + ) + .replace( + /\n\s*if ENV\['EXPO_MLKIT_OCR_DISABLE_MLKIT'\] == '1'\s*\n\s*installer\.pods_project\.targets\.each do \|target\|[\s\S]*?\n\s*end\s*\n/g, + "\n", + ); +} + +function insertDisableLine(podfile) { + const lines = podfile + .split(/\r?\n/) + .filter((line) => line.trim() !== DISABLE_LINE); + + let insertAt = 0; + while (insertAt < lines.length && lines[insertAt].trim().startsWith("#")) { + insertAt += 1; + } + + lines.splice(insertAt, 0, DISABLE_LINE); + return lines.join("\n"); +} + +/** @type {import('@expo/config-plugins').ConfigPlugin<{ iosEngine?: "auto" | "mlkit" | "vision", disableMlkitOnSimulator?: boolean }>} */ +function withExpoMlkitOcrEnv(config, props = {}) { + return withDangerousMod(config, [ + "ios", + async (config) => { + const podfilePath = path.join(config.modRequest.platformProjectRoot, "Podfile"); + if (!fs.existsSync(podfilePath)) { + return config; + } + + const iosEngine = resolveIosEngine(props); + const shouldDisableMlkit = + iosEngine !== "mlkit" || props.disableMlkitOnSimulator === true; + + let podfile = fs.readFileSync(podfilePath, "utf8"); + podfile = stripMarkedBlock(podfile); + podfile = stripOrphanedMlkitArchPatch(podfile); + + if (shouldDisableMlkit) { + podfile = insertDisableLine(podfile); + } else { + podfile = podfile + .split(/\r?\n/) + .filter((line) => line.trim() !== DISABLE_LINE) + .join("\n"); + } + + fs.writeFileSync(podfilePath, podfile.endsWith("\n") ? podfile : `${podfile}\n`); + return config; + }, + ]); +} + +module.exports = createRunOncePlugin( + withExpoMlkitOcrEnv, + "beenvoice-expo-mlkit-ocr-env", + pkg.version, +);