diff --git a/cli/src/config.ts b/cli/src/config.ts index bfd67df4b..05dd86393 100644 --- a/cli/src/config.ts +++ b/cli/src/config.ts @@ -1,4 +1,4 @@ -import { pathExists, readJSON } from '@ionic/utils-fs'; +import { pathExists, readFile, readJSON } from '@ionic/utils-fs'; import Debug from 'debug'; import { dirname, join, relative, resolve } from 'path'; @@ -14,6 +14,7 @@ import type { } from './definitions'; import { OS } from './definitions'; import { fatal, isFatal } from './errors'; +import { logger } from './log'; import { tryFn } from './util/fn'; import { resolveNode, requireTS } from './util/node'; import { lazy } from './util/promise'; @@ -240,11 +241,19 @@ async function loadIOSConfig( const nativeProjectDir = 'App'; const nativeProjectDirAbs = resolve(platformDirAbs, nativeProjectDir); const nativeTargetDir = `${nativeProjectDir}/App`; + const nativeTargetDirAbs = resolve(platformDirAbs, nativeTargetDir); const nativeXcodeProjDir = `${nativeProjectDir}/App.xcodeproj`; + const nativeXcodeProjDirAbs = resolve(platformDirAbs, nativeXcodeProjDir); const nativeXcodeWorkspaceDirAbs = lazy(() => determineXcodeWorkspaceDirAbs(nativeProjectDirAbs), ); - const webDir = `${nativeProjectDir}/public`; + const webDirAbs = lazy(() => + determineIOSWebDirAbs( + nativeProjectDirAbs, + nativeTargetDirAbs, + nativeXcodeProjDirAbs, + ), + ); const cordovaPluginsDir = 'capacitor-cordova-ios-plugins'; return { @@ -257,15 +266,15 @@ async function loadIOSConfig( nativeProjectDir, nativeProjectDirAbs, nativeTargetDir, - nativeTargetDirAbs: resolve(platformDirAbs, nativeTargetDir), + nativeTargetDirAbs, nativeXcodeProjDir, - nativeXcodeProjDirAbs: resolve(platformDirAbs, nativeXcodeProjDir), + nativeXcodeProjDirAbs, nativeXcodeWorkspaceDir: lazy(async () => relative(platformDirAbs, await nativeXcodeWorkspaceDirAbs), ), nativeXcodeWorkspaceDirAbs, - webDir, - webDirAbs: resolve(platformDirAbs, webDir), + webDir: lazy(async () => relative(platformDirAbs, await webDirAbs)), + webDirAbs, podPath, }; } @@ -312,6 +321,41 @@ async function determineXcodeWorkspaceDirAbs( return xcodeDir; } +async function determineIOSWebDirAbs( + nativeProjectDirAbs: string, + nativeTargetDirAbs: string, + nativeXcodeProjDirAbs: string, +): Promise { + const re = /path\s=\spublic[\s\S]+?sourceTree\s=\s([^;]+)/; + const pbxprojPath = resolve(nativeXcodeProjDirAbs, 'project.pbxproj'); + const pbxproj = await readFile(pbxprojPath, { encoding: 'utf8' }); + + const m = pbxproj.match(re); + + if (m === null) { + fatal(`Unrecognized structure in ${c.strong(pbxprojPath)}`); + } + + const [, sourceTree] = m; + + if (sourceTree === 'SOURCE_ROOT') { + logger.warn( + `Using the iOS project root for the ${c.strong( + 'public', + )} directory is deprecated.\n` + + `Please follow the Upgrade Guide to move ${c.strong( + 'public', + )} inside the iOS target directory: ${c.strong( + 'https://capacitorjs.com/docs/v3/updating/3-0#move-public-into-the-ios-target-directory', + )}`, + ); + + return resolve(nativeProjectDirAbs, 'public'); + } + + return resolve(nativeTargetDirAbs, 'public'); +} + async function determineAndroidStudioPath(os: OS): Promise { if (process.env.CAPACITOR_ANDROID_STUDIO_PATH) { return process.env.CAPACITOR_ANDROID_STUDIO_PATH; diff --git a/cli/src/cordova.ts b/cli/src/cordova.ts index 7771b165e..ad4a38a55 100644 --- a/cli/src/cordova.ts +++ b/cli/src/cordova.ts @@ -128,7 +128,7 @@ export async function copyPluginsJS( cordovaPlugins: Plugin[], platform: string, ): Promise { - const webDir = getWebDir(config, platform); + const webDir = await getWebDir(config, platform); const pluginsDir = join(webDir, 'plugins'); const cordovaPluginsJSFile = join(webDir, 'cordova_plugins.js'); await removePluginFiles(config, platform); @@ -189,22 +189,26 @@ export async function copyCordovaJS( ); } - return copy(cordovaPath, join(getWebDir(config, platform), 'cordova.js')); + return copy( + cordovaPath, + join(await getWebDir(config, platform), 'cordova.js'), + ); } export async function createEmptyCordovaJS( config: Config, platform: string, ): Promise { - await writeFile(join(getWebDir(config, platform), 'cordova.js'), ''); - await writeFile(join(getWebDir(config, platform), 'cordova_plugins.js'), ''); + const webDir = await getWebDir(config, platform); + await writeFile(join(webDir, 'cordova.js'), ''); + await writeFile(join(webDir, 'cordova_plugins.js'), ''); } export async function removePluginFiles( config: Config, platform: string, ): Promise { - const webDir = getWebDir(config, platform); + const webDir = await getWebDir(config, platform); const pluginsDir = join(webDir, 'plugins'); const cordovaPluginsJSFile = join(webDir, 'cordova_plugins.js'); await remove(pluginsDir); @@ -271,7 +275,7 @@ export async function autoGenerateConfig( await writeFile(cordovaConfigXMLFile, content); } -function getWebDir(config: Config, platform: string): string { +async function getWebDir(config: Config, platform: string): Promise { if (platform === 'ios') { return config.ios.webDirAbs; } @@ -286,7 +290,7 @@ export async function handleCordovaPluginsJS( config: Config, platform: string, ): Promise { - if (!(await pathExists(getWebDir(config, platform)))) { + if (!(await pathExists(await getWebDir(config, platform)))) { await copyTask(config, platform); } if (cordovaPlugins.length > 0) { diff --git a/cli/src/definitions.ts b/cli/src/definitions.ts index 92c559e3b..6f4f8e801 100644 --- a/cli/src/definitions.ts +++ b/cli/src/definitions.ts @@ -96,8 +96,8 @@ export interface IOSConfig extends PlatformConfig { readonly cordovaPluginsDirAbs: string; readonly minVersion: string; readonly podPath: string; - readonly webDir: string; - readonly webDirAbs: string; + readonly webDir: Promise; + readonly webDirAbs: Promise; readonly nativeProjectDir: string; readonly nativeProjectDirAbs: string; readonly nativeTargetDir: string; diff --git a/cli/src/tasks/copy.ts b/cli/src/tasks/copy.ts index b22a5a6a7..d5c834f14 100644 --- a/cli/src/tasks/copy.ts +++ b/cli/src/tasks/copy.ts @@ -66,7 +66,7 @@ export async function copy( } if (platformName === config.ios.name) { - await copyWebDir(config, config.ios.webDirAbs); + await copyWebDir(config, await config.ios.webDirAbs); await copyCapacitorConfig(config, config.ios.nativeTargetDirAbs); const cordovaPlugins = await getCordovaPlugins(config, platformName); await handleCordovaPluginsJS(cordovaPlugins, config, platformName); diff --git a/cli/test/update.ios.spec.ts b/cli/test/update.ios.spec.ts index c3975d1f9..317e5cce5 100644 --- a/cli/test/update.ios.spec.ts +++ b/cli/test/update.ios.spec.ts @@ -31,7 +31,7 @@ describe.each([false, true])('Update: iOS (monoRepoLike: %p)', monoRepoLike => { it('Should install Cordova plugin JS', async () => { const cordovaPluginJSContent = await FS.read( - 'ios/App/public/cordova_plugins.js', + 'ios/App/App/public/cordova_plugins.js', ); const regex = new RegExp(CORDOVA_PLUGIN_ID); expect(regex.test(cordovaPluginJSContent)).toBe(true); diff --git a/ios-template/.gitignore b/ios-template/.gitignore index 7a8999263..75e8c5aec 100644 --- a/ios-template/.gitignore +++ b/ios-template/.gitignore @@ -1,7 +1,7 @@ App/build App/Pods -App/public App/Podfile.lock +App/App/public DerivedData xcuserdata diff --git a/ios-template/App/App.xcodeproj/project.pbxproj b/ios-template/App/App.xcodeproj/project.pbxproj index b97ce9e6b..f83db6776 100644 --- a/ios-template/App/App.xcodeproj/project.pbxproj +++ b/ios-template/App/App.xcodeproj/project.pbxproj @@ -26,7 +26,7 @@ 504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = SOURCE_ROOT; }; + 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; diff --git a/ios-template/App/public/.gitkeep b/ios-template/App/App/public/.gitkeep similarity index 100% rename from ios-template/App/public/.gitkeep rename to ios-template/App/App/public/.gitkeep