1import {
2  ConfigPlugin,
3  withEntitlementsPlist,
4  IOSConfig,
5  withXcodeProject,
6  XcodeProject,
7} from 'expo/config-plugins';
8import { copyFileSync } from 'fs';
9import { basename, resolve } from 'path';
10
11import { NotificationsPluginProps } from './withNotifications';
12
13const ERROR_MSG_PREFIX = 'An error occurred while configuring iOS notifications. ';
14
15export const withNotificationsIOS: ConfigPlugin<NotificationsPluginProps> = (
16  config,
17  { mode = 'development', sounds = [] }
18) => {
19  config = withEntitlementsPlist(config, (config) => {
20    config.modResults['aps-environment'] = mode;
21    return config;
22  });
23  config = withNotificationSounds(config, { sounds });
24  return config;
25};
26
27export const withNotificationSounds: ConfigPlugin<{ sounds: string[] }> = (config, { sounds }) => {
28  return withXcodeProject(config, (config) => {
29    setNotificationSounds(config.modRequest.projectRoot, {
30      sounds,
31      project: config.modResults,
32      projectName: config.modRequest.projectName,
33    });
34    return config;
35  });
36};
37
38/**
39 * Save sound files to the Xcode project root and add them to the Xcode project.
40 */
41export function setNotificationSounds(
42  projectRoot: string,
43  {
44    sounds,
45    project,
46    projectName,
47  }: { sounds: string[]; project: XcodeProject; projectName: string | undefined }
48): XcodeProject {
49  if (!projectName) {
50    throw new Error(ERROR_MSG_PREFIX + `Unable to find iOS project name.`);
51  }
52  if (!Array.isArray(sounds)) {
53    throw new Error(
54      ERROR_MSG_PREFIX +
55        `Must provide an array of sound files in your app config, found ${typeof sounds}.`
56    );
57  }
58  const sourceRoot = IOSConfig.Paths.getSourceRoot(projectRoot);
59  for (const soundFileRelativePath of sounds) {
60    const fileName = basename(soundFileRelativePath);
61    const sourceFilepath = resolve(projectRoot, soundFileRelativePath);
62    const destinationFilepath = resolve(sourceRoot, fileName);
63
64    // Since it's possible that the filename is the same, but the
65    // file itself id different, let's copy it regardless
66    copyFileSync(sourceFilepath, destinationFilepath);
67    if (!project.hasFile(`${projectName}/${fileName}`)) {
68      project = IOSConfig.XcodeUtils.addResourceFileToGroup({
69        filepath: `${projectName}/${fileName}`,
70        groupName: projectName,
71        isBuildFile: true,
72        project,
73      });
74    }
75  }
76
77  return project;
78}
79