Files
react-native/packages/assets/path-support.js
T
Moti Zilberman f22e6033d9 Support nonstandard pixel densities for Android drawables
Summary:
Adds functionality to RN's built-in version of the `getAndroidAssetSuffix` function. Open source uses a [fork of this code](https://github.com/react-native-community/cli/blob/df55a78f2d27e3443f15b15b87459b54a78e2c47/packages/cli/src/commands/bundle/assetPathUtils.ts#L19-L36) as part of the RN CLI and is therefore unaffected.

Specifically, we can now package drawable assets for Android with nonstandard pixel densities by placing them in [`drawable-<nnn>dpi`](https://developer.android.com/guide/topics/resources/providing-resources#:~:text=nnndpi), where `nnn` is a number representing a pixel density. Previously using nonstandard scale factors like `1.25x` would be a build-time error when building for Android.

We could send a corresponding PR to the RN CLI, but [Gradle doesn't support this convention](https://issuetracker.google.com/issues/72884435) (although it is documented and supported by Android) so it may not be of much use in OSS right away.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D30784087

fbshipit-source-id: ea82f924d14a316702cabba759722cf26f69eb21
2021-09-09 08:19:42 -07:00

92 lines
2.3 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
'use strict';
import type {PackagerAsset} from './registry.js';
const androidScaleSuffix = {
'0.75': 'ldpi',
'1': 'mdpi',
'1.5': 'hdpi',
'2': 'xhdpi',
'3': 'xxhdpi',
'4': 'xxxhdpi',
};
const ANDROID_BASE_DENSITY = 160;
/**
* FIXME: using number to represent discrete scale numbers is fragile in essence because of
* floating point numbers imprecision.
*/
function getAndroidAssetSuffix(scale: number): string {
if (scale.toString() in androidScaleSuffix) {
return androidScaleSuffix[scale.toString()];
}
// NOTE: Android Gradle Plugin does not fully support the nnndpi format.
// See https://issuetracker.google.com/issues/72884435
if (Number.isFinite(scale) && scale > 0) {
return Math.round(scale * ANDROID_BASE_DENSITY) + 'dpi';
}
throw new Error('no such scale ' + scale.toString());
}
// See https://developer.android.com/guide/topics/resources/drawable-resource.html
const drawableFileTypes = new Set([
'gif',
'jpeg',
'jpg',
'png',
'svg',
'webp',
'xml',
]);
function getAndroidResourceFolderName(
asset: PackagerAsset,
scale: number,
): string | $TEMPORARY$string<'raw'> {
if (!drawableFileTypes.has(asset.type)) {
return 'raw';
}
const suffix = getAndroidAssetSuffix(scale);
if (!suffix) {
throw new Error(
"Don't know which android drawable suffix to use for scale: " +
scale +
'\nAsset: ' +
JSON.stringify(asset, null, '\t') +
'\nPossible scales are:' +
JSON.stringify(androidScaleSuffix, null, '\t'),
);
}
return 'drawable-' + suffix;
}
function getAndroidResourceIdentifier(asset: PackagerAsset): string {
return (getBasePath(asset) + '/' + asset.name)
.toLowerCase()
.replace(/\//g, '_') // Encode folder structure in file name
.replace(/([^a-z0-9_])/g, '') // Remove illegal chars
.replace(/^assets_/, ''); // Remove "assets_" prefix
}
function getBasePath(asset: PackagerAsset): string {
const basePath = asset.httpServerLocation;
return basePath.startsWith('/') ? basePath.substr(1) : basePath;
}
module.exports = {
getAndroidResourceFolderName,
getAndroidResourceIdentifier,
getBasePath,
};