1const { getConfig, getNameFromConfig } = require('expo/config');
2// Use root to work better with create-react-app
3const DEFAULT_LANGUAGE_ISO_CODE = `en`;
4const DEFAULT_DISPLAY = 'standalone';
5const DEFAULT_STATUS_BAR = 'black-translucent';
6const DEFAULT_PREFER_RELATED_APPLICATIONS = true;
7// Convert expo value to PWA value
8function ensurePWAorientation(orientation) {
9  if (orientation && typeof orientation === 'string') {
10    const webOrientation = orientation.toLowerCase();
11    if (webOrientation !== 'default') {
12      return webOrientation;
13    }
14  }
15  return undefined;
16}
17
18const RESTRICTED_MANIFEST_FIELDS = [
19  // Omit app.json properties that get removed during the native build
20  'facebookScheme',
21  'facebookAppId',
22  'facebookDisplayName',
23  // Remove iOS and Android.
24  'ios',
25  'android',
26  // Hide internal / build values
27  'plugins',
28  'hooks',
29  '_internal',
30  // Remove metro-specific values
31  'assetBundlePatterns',
32];
33function getExpoConstantsManifest(projectRoot) {
34  const { exp } = getConfig(projectRoot, {
35    isPublicConfig: true,
36    skipSDKVersionRequirement: true,
37  });
38  const manifest = ensurePWAConfig(exp);
39  for (const field of RESTRICTED_MANIFEST_FIELDS) {
40    delete manifest[field];
41  }
42  return manifest;
43}
44function applyWebDefaults(appJSON) {
45  // For RN CLI support
46  // @ts-ignore: expo object doesn't exist on ExpoConfig
47  const appManifest = appJSON.expo || appJSON || {};
48  const { web: webManifest = {}, splash = {}, ios = {}, android = {} } = appManifest;
49  // rn-cli apps use a displayName value as well.
50  const { appName, webName } = getNameFromConfig(appJSON);
51  const languageISOCode = webManifest.lang || DEFAULT_LANGUAGE_ISO_CODE;
52  const primaryColor = appManifest.primaryColor;
53  const description = appManifest.description;
54  // The theme_color sets the color of the tool bar, and may be reflected in the app's preview in task switchers.
55  const webThemeColor = webManifest.themeColor || primaryColor;
56  const dir = webManifest.dir;
57  const shortName = webManifest.shortName || webName;
58  const display = webManifest.display || DEFAULT_DISPLAY;
59  const startUrl = webManifest.startUrl;
60  const { scope, crossorigin } = webManifest;
61  const barStyle = webManifest.barStyle || DEFAULT_STATUS_BAR;
62  const orientation = ensurePWAorientation(webManifest.orientation || appManifest.orientation);
63  /**
64   * **Splash screen background color**
65   * `https://developers.google.com/web/fundamentals/web-app-manifest/#splash-screen`
66   * The background_color should be the same color as the load page,
67   * to provide a smooth transition from the splash screen to your app.
68   */
69  const backgroundColor = webManifest.backgroundColor || splash.backgroundColor; // No default background color
70  /**
71   *
72   * https://developer.mozilla.org/en-US/docs/Web/Manifest#prefer_related_applications
73   * Specifies a boolean value that hints for the user agent to indicate
74   * to the user that the specified native applications (see below) are recommended over the website.
75   * This should only be used if the related native apps really do offer something that the website can't... like Expo ;)
76   *
77   * >> The banner won't show up if the app is already installed:
78   * https://github.com/GoogleChrome/samples/issues/384#issuecomment-326387680
79   */
80  const preferRelatedApplications =
81    webManifest.preferRelatedApplications === undefined
82      ? DEFAULT_PREFER_RELATED_APPLICATIONS
83      : webManifest.preferRelatedApplications;
84  const relatedApplications = inferWebRelatedApplicationsFromConfig(appManifest);
85  return {
86    ...appManifest,
87    name: appName,
88    description,
89    primaryColor,
90    // Ensure these objects exist
91    ios: {
92      ...ios,
93    },
94    android: {
95      ...android,
96    },
97    web: {
98      ...webManifest,
99      meta: undefined,
100      build: undefined,
101      scope,
102      crossorigin,
103      description,
104      preferRelatedApplications,
105      relatedApplications,
106      startUrl,
107      shortName,
108      display,
109      orientation,
110      dir,
111      barStyle,
112      backgroundColor,
113      themeColor: webThemeColor,
114      lang: languageISOCode,
115      name: webName,
116    },
117  };
118}
119/**
120 * https://developer.mozilla.org/en-US/docs/Web/Manifest#related_applications
121 * An array of native applications that are installable by, or accessible to, the underlying platform
122 * for example, a native Android application obtainable through the Google Play Store.
123 * Such applications are intended to be alternatives to the
124 * website that provides similar/equivalent functionality — like the native app version of the website.
125 */
126function inferWebRelatedApplicationsFromConfig({ web = {}, ios = {}, android = {} }) {
127  const relatedApplications = web.relatedApplications || [];
128  const { bundleIdentifier, appStoreUrl } = ios;
129  if (bundleIdentifier) {
130    const PLATFORM_ITUNES = 'itunes';
131    const iosApp = relatedApplications.some(({ platform }) => platform === PLATFORM_ITUNES);
132    if (!iosApp) {
133      relatedApplications.push({
134        platform: PLATFORM_ITUNES,
135        url: appStoreUrl,
136        id: bundleIdentifier,
137      });
138    }
139  }
140  const { package: androidPackage, playStoreUrl } = android;
141  if (androidPackage) {
142    const PLATFORM_PLAY = 'play';
143    const alreadyHasAndroidApp = relatedApplications.some(
144      ({ platform }) => platform === PLATFORM_PLAY
145    );
146    if (!alreadyHasAndroidApp) {
147      relatedApplications.push({
148        platform: PLATFORM_PLAY,
149        url: playStoreUrl || `http://play.google.com/store/apps/details?id=${androidPackage}`,
150        id: androidPackage,
151      });
152    }
153  }
154  return relatedApplications;
155}
156function ensurePWAConfig(appJSON) {
157  const config = applyWebDefaults(appJSON);
158  return config;
159}
160
161module.exports = {
162  getExpoConstantsManifest,
163};
164