18d307f52SEvan Baconimport { IOSConfig } from '@expo/config-plugins';
28d307f52SEvan Baconimport plist from '@expo/plist';
38d307f52SEvan Baconimport fs from 'fs';
48d307f52SEvan Bacon
58d307f52SEvan Baconimport { AppIdResolver } from '../AppIdResolver';
68d307f52SEvan Bacon
760392ac6SEvan Baconconst debug = require('debug')('expo:start:platforms:ios:AppleAppIdResolver') as typeof console.log;
860392ac6SEvan Bacon
98d307f52SEvan Bacon/** Resolves the iOS bundle identifier from the Expo config or native files. */
108d307f52SEvan Baconexport class AppleAppIdResolver extends AppIdResolver {
118d307f52SEvan Bacon  constructor(projectRoot: string) {
128d307f52SEvan Bacon    super(projectRoot, 'ios', 'ios.bundleIdentifier');
138d307f52SEvan Bacon  }
148d307f52SEvan Bacon
15*def098a4SEvan Bacon  /** @return `true` if the app has valid `*.pbxproj` file */
168d307f52SEvan Bacon  async hasNativeProjectAsync(): Promise<boolean> {
178d307f52SEvan Bacon    try {
1860392ac6SEvan Bacon      // Never returns nullish values.
19*def098a4SEvan Bacon      return !!IOSConfig.Paths.getAllPBXProjectPaths(this.projectRoot).length;
2060392ac6SEvan Bacon    } catch (error: any) {
2160392ac6SEvan Bacon      debug('Expected error checking for native project:', error);
2260392ac6SEvan Bacon      return false;
238d307f52SEvan Bacon    }
248d307f52SEvan Bacon  }
258d307f52SEvan Bacon
268d307f52SEvan Bacon  async resolveAppIdFromNativeAsync(): Promise<string | null> {
278d307f52SEvan Bacon    // Check xcode project
288d307f52SEvan Bacon    try {
298d307f52SEvan Bacon      const bundleId = IOSConfig.BundleIdentifier.getBundleIdentifierFromPbxproj(this.projectRoot);
308d307f52SEvan Bacon      if (bundleId) {
318d307f52SEvan Bacon        return bundleId;
328d307f52SEvan Bacon      }
3360392ac6SEvan Bacon    } catch (error: any) {
3460392ac6SEvan Bacon      debug('Expected error resolving the bundle identifier from the pbxproj:', error);
3560392ac6SEvan Bacon    }
368d307f52SEvan Bacon
378d307f52SEvan Bacon    // Check Info.plist
388d307f52SEvan Bacon    try {
398d307f52SEvan Bacon      const infoPlistPath = IOSConfig.Paths.getInfoPlistPath(this.projectRoot);
408d307f52SEvan Bacon      const data = await plist.parse(fs.readFileSync(infoPlistPath, 'utf8'));
418d307f52SEvan Bacon      if (data.CFBundleIdentifier && !data.CFBundleIdentifier.startsWith('$(')) {
428d307f52SEvan Bacon        return data.CFBundleIdentifier;
438d307f52SEvan Bacon      }
4460392ac6SEvan Bacon    } catch (error) {
4560392ac6SEvan Bacon      debug('Expected error resolving the bundle identifier from the project Info.plist:', error);
4660392ac6SEvan Bacon    }
478d307f52SEvan Bacon
488d307f52SEvan Bacon    return null;
498d307f52SEvan Bacon  }
508d307f52SEvan Bacon}
51