94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import { type ImageOptions, generateImageAsync } from '@expo/image-utils';
|
|
import type { ExpoConfig } from 'expo/config';
|
|
import {
|
|
type ConfigPlugin,
|
|
IOSConfig,
|
|
type XcodeProject,
|
|
withXcodeProject,
|
|
} from 'expo/config-plugins';
|
|
import fs from 'fs/promises';
|
|
import path from 'path';
|
|
|
|
import { type ContentsJsonImage, writeContentsJsonAsync } from './AssetContents';
|
|
import { IMAGE_TYPES, resolveAssetPaths, validateAssets } from './utils';
|
|
|
|
const IMAGE_DIR = 'Images.xcassets';
|
|
|
|
export const withAssetsIos: ConfigPlugin<string[]> = (config, assets) => {
|
|
config = addAssetsToTarget(config, assets);
|
|
return config;
|
|
};
|
|
|
|
function addAssetsToTarget(config: ExpoConfig, assets: string[]) {
|
|
return withXcodeProject(config, async (config) => {
|
|
const resolvedAssets = await resolveAssetPaths(assets, config.modRequest.projectRoot);
|
|
const validAssets = validateAssets(resolvedAssets, 'ios');
|
|
const project = config.modResults;
|
|
const platformProjectRoot = config.modRequest.platformProjectRoot;
|
|
IOSConfig.XcodeUtils.ensureGroupRecursively(project, 'Resources');
|
|
|
|
const images = validAssets.filter((asset) => IMAGE_TYPES.includes(path.extname(asset)));
|
|
const assetsForResourcesDir = validAssets.filter(
|
|
(asset) => !IMAGE_TYPES.includes(path.extname(asset))
|
|
);
|
|
|
|
await addImageAssets(images, config.modRequest.projectRoot);
|
|
addResourceFiles(project, platformProjectRoot, assetsForResourcesDir);
|
|
|
|
return config;
|
|
});
|
|
}
|
|
|
|
function addResourceFiles(project: XcodeProject, platformRoot: string, assets: string[]) {
|
|
for (const asset of assets) {
|
|
const assetPath = path.relative(platformRoot, asset);
|
|
IOSConfig.XcodeUtils.addResourceFileToGroup({
|
|
filepath: assetPath,
|
|
groupName: 'Resources',
|
|
project,
|
|
isBuildFile: true,
|
|
verbose: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
async function addImageAssets(assets: string[], root: string) {
|
|
const iosNamedProjectRoot = IOSConfig.Paths.getSourceRoot(root);
|
|
for (const asset of assets) {
|
|
const name = path.basename(asset, path.extname(asset));
|
|
const image = path.basename(asset);
|
|
|
|
const assetPath = path.resolve(iosNamedProjectRoot, `${IMAGE_DIR}/${name}.imageset`);
|
|
await fs.mkdir(assetPath, { recursive: true });
|
|
|
|
const buffer = await generateImageAsync({ projectRoot: root }, {
|
|
src: asset,
|
|
} as unknown as ImageOptions);
|
|
await fs.writeFile(path.resolve(assetPath, image), buffer.source);
|
|
|
|
await writeContentsJsonFileAsync({
|
|
assetPath,
|
|
image,
|
|
});
|
|
}
|
|
}
|
|
|
|
async function writeContentsJsonFileAsync({
|
|
assetPath,
|
|
image,
|
|
}: {
|
|
assetPath: string;
|
|
image: string;
|
|
}) {
|
|
const images = buildContentsJsonImages({ image });
|
|
await writeContentsJsonAsync(assetPath, { images });
|
|
}
|
|
|
|
function buildContentsJsonImages({ image }: { image: string }): ContentsJsonImage[] {
|
|
return [
|
|
{ idiom: 'universal', filename: image, scale: '1x' },
|
|
{ idiom: 'universal', scale: '2x' },
|
|
{ idiom: 'universal', scale: '3x' },
|
|
];
|
|
}
|