mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-16 02:44:51 +00:00
170 lines
4.5 KiB
TypeScript
170 lines
4.5 KiB
TypeScript
import {
|
|
AndroidConfig,
|
|
type ConfigPlugin,
|
|
withAndroidManifest,
|
|
withMainActivity,
|
|
} from "@expo/config-plugins";
|
|
import {
|
|
addImports,
|
|
appendContentsInsideDeclarationBlock,
|
|
} from "@expo/config-plugins/build/android/codeMod";
|
|
|
|
const MODE_MARKER = "OmniView.onActivityPipModeChanged(";
|
|
const UI_STATE_MARKER = "OmniView.onActivityPipTransitionToPip(";
|
|
|
|
function patchMainActivityForPip(
|
|
mainActivity: string,
|
|
language: "java" | "kt",
|
|
): string {
|
|
const isJava = language === "java";
|
|
|
|
if (
|
|
mainActivity.includes(MODE_MARKER) &&
|
|
mainActivity.includes(UI_STATE_MARKER)
|
|
) {
|
|
return mainActivity;
|
|
}
|
|
|
|
const withRequiredImports = addImports(
|
|
mainActivity,
|
|
[
|
|
"android.app.PictureInPictureUiState",
|
|
"android.os.Build",
|
|
"dev.zoriya.omni.OmniView",
|
|
],
|
|
isJava,
|
|
);
|
|
|
|
let output = withRequiredImports;
|
|
|
|
if (!output.includes(MODE_MARKER)) {
|
|
const modeChangedBlock = isJava
|
|
? [
|
|
"\n @Override",
|
|
" public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {",
|
|
" super.onPictureInPictureModeChanged(isInPictureInPictureMode);",
|
|
" OmniView.onActivityPipModeChanged(this, isInPictureInPictureMode);",
|
|
" }\n",
|
|
]
|
|
: [
|
|
"\n override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {",
|
|
" super.onPictureInPictureModeChanged(isInPictureInPictureMode)",
|
|
" OmniView.onActivityPipModeChanged(this, isInPictureInPictureMode)",
|
|
" }\n",
|
|
];
|
|
|
|
output = appendContentsInsideDeclarationBlock(
|
|
output,
|
|
"class MainActivity",
|
|
modeChangedBlock.join("\n"),
|
|
);
|
|
}
|
|
|
|
if (!output.includes(UI_STATE_MARKER)) {
|
|
const uiStateChangedBlock = isJava
|
|
? [
|
|
"\n @Override",
|
|
" public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) {",
|
|
" super.onPictureInPictureUiStateChanged(pipState);",
|
|
" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && pipState.isTransitioningToPip()) {",
|
|
" OmniView.onActivityPipTransitionToPip(this);",
|
|
" }",
|
|
" }\n",
|
|
]
|
|
: [
|
|
"\n override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {",
|
|
" super.onPictureInPictureUiStateChanged(pipState)",
|
|
" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && pipState.isTransitioningToPip) {",
|
|
" OmniView.onActivityPipTransitionToPip(this)",
|
|
" }",
|
|
" }\n",
|
|
];
|
|
|
|
output = appendContentsInsideDeclarationBlock(
|
|
output,
|
|
"class MainActivity",
|
|
uiStateChangedBlock.join("\n"),
|
|
);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
function ensureUsesFeature(
|
|
androidManifest: AndroidConfig.Manifest.AndroidManifest,
|
|
featureName: string,
|
|
required: "true" | "false",
|
|
): void {
|
|
const usesFeature = androidManifest.manifest["uses-feature"] ?? [];
|
|
const existing = usesFeature.find(
|
|
(feature) => feature.$["android:name"] === featureName,
|
|
);
|
|
|
|
if (existing) {
|
|
existing.$["android:required"] = required;
|
|
} else {
|
|
usesFeature.push({
|
|
$: {
|
|
"android:name": featureName,
|
|
"android:required": required,
|
|
},
|
|
});
|
|
}
|
|
|
|
androidManifest.manifest["uses-feature"] = usesFeature;
|
|
}
|
|
|
|
function ensureConfigChanges(
|
|
mainActivity: AndroidConfig.Manifest.ManifestActivity,
|
|
): void {
|
|
const requiredChanges = [
|
|
"screenSize",
|
|
"smallestScreenSize",
|
|
"screenLayout",
|
|
"orientation",
|
|
];
|
|
const existing = mainActivity.$["android:configChanges"] ?? "";
|
|
const existingSet = new Set(
|
|
existing
|
|
.split("|")
|
|
.map((item) => item.trim())
|
|
.filter(Boolean),
|
|
);
|
|
|
|
requiredChanges.forEach((item) => existingSet.add(item));
|
|
mainActivity.$["android:configChanges"] = Array.from(existingSet).join("|");
|
|
}
|
|
|
|
function patchManifestForPip(
|
|
androidManifest: AndroidConfig.Manifest.AndroidManifest,
|
|
): AndroidConfig.Manifest.AndroidManifest {
|
|
ensureUsesFeature(
|
|
androidManifest,
|
|
"android.software.picture_in_picture",
|
|
"false",
|
|
);
|
|
|
|
const mainActivity =
|
|
AndroidConfig.Manifest.getMainActivityOrThrow(androidManifest);
|
|
mainActivity.$["android:supportsPictureInPicture"] = "true";
|
|
mainActivity.$["android:resizeableActivity"] = "true";
|
|
ensureConfigChanges(mainActivity);
|
|
|
|
return androidManifest;
|
|
}
|
|
|
|
export const withPip: ConfigPlugin = (config) => {
|
|
const withMainActivityPatched = withMainActivity(config, (activityConfig) => {
|
|
activityConfig.modResults.contents = patchMainActivityForPip(
|
|
activityConfig.modResults.contents,
|
|
activityConfig.modResults.language,
|
|
);
|
|
return activityConfig;
|
|
});
|
|
|
|
return withAndroidManifest(withMainActivityPatched, (manifestConfig) => {
|
|
manifestConfig.modResults = patchManifestForPip(manifestConfig.modResults);
|
|
return manifestConfig;
|
|
});
|
|
};
|