1import { AndroidConfig } from '@expo/config-plugins';
2
3import { AppIdResolver } from '../AppIdResolver';
4
5const debug = require('debug')(
6  'expo:start:platforms:android:AndroidAppIdResolver'
7) as typeof console.log;
8
9/** Resolves the Android package name from the Expo config or native files. */
10export class AndroidAppIdResolver extends AppIdResolver {
11  constructor(projectRoot: string) {
12    super(projectRoot, 'android', 'android.package');
13  }
14
15  async hasNativeProjectAsync(): Promise<boolean> {
16    try {
17      await AndroidConfig.Paths.getProjectPathOrThrowAsync(this.projectRoot);
18      return true;
19    } catch (error: any) {
20      debug('Expected error checking for native project:', error);
21      return false;
22    }
23  }
24
25  async resolveAppIdFromNativeAsync(): Promise<string | null> {
26    const applicationIdFromGradle = await AndroidConfig.Package.getApplicationIdAsync(
27      this.projectRoot
28    ).catch(() => null);
29    if (applicationIdFromGradle) {
30      return applicationIdFromGradle;
31    }
32
33    try {
34      const filePath = await AndroidConfig.Paths.getAndroidManifestAsync(this.projectRoot);
35      const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(filePath);
36      // Assert MainActivity defined.
37      await AndroidConfig.Manifest.getMainActivityOrThrow(androidManifest);
38      if (androidManifest.manifest?.$?.package) {
39        return androidManifest.manifest.$.package;
40      }
41    } catch (error: any) {
42      debug('Expected error resolving the package name from the AndroidManifest.xml:', error);
43    }
44
45    return null;
46  }
47}
48