🏞️

[React Native] Expo Android アプリの背景を透明にする

2023/11/27に公開

まずは空プロジェクト作成

create-expo-app で作成したプロジェクトの背景を透過にしてみたいと思います。

npx create-expo-app test

前準備

背景の透過は Expo Go クライアントでは実行できないため開発用の Expo クライアントを作成する必要があります。

https://docs.expo.dev/develop/development-builds/create-a-build/

ローカルでビルドする場合はこちらを参照

https://zenn.dev/tadaedo/scraps/6f989f2a104f76

今回はビルドについては割愛します。

手順1: View に透過色を設定する

スタイルに設定されている背景色を透明にします。

App.js
const styles = StyleSheet.create({
  container: {
    flex: 1,
-   backgroundColor: '#fff',
+   backgroundColor: '#00000000',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

View の背景を透明にしただけでは全然効果がありませんので app.json の背景も指定します。

app.json
{
  "expo": {
    ...
    "android": {
      ...
+     "backgroundColor": "#00000000"
    },
    ...
}

app.json に backgroundColor を指定して開発用 Expo クライアントをビルドすると、backgroundColor が Android アプリの colors と style に紐付けが行われます。

android/app/src/main/res/values/colors.xml
<resources>
  ...
  <color name="activityBackground">#00000000</color>
</resources>
android/app/src/main/res/values/styles.xml
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:windowBackground">@color/activityBackground</item>
  </style>

ここで Expo クライアントをビルドして実行してみます。

真っ黒です。透過は正しく設定できているのですが、アプリ実行中はシステムの壁紙が表示されないため真っ黒な表示になってしまい透明になった実感が全くありません。

アプリ実行中も壁紙を表示するためには Android の styles に windowShowWallpaper を追加する必要があります。

android/app/src/main/res/values/styles.xml
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:windowBackground">@color/activityBackground</item>
    <!-- これが必要: <item name="android:windowShowWallpaper">true</item> -->
  </style>

手順2: Plugin で Styles を動的に編集

app.json だけでは styles に windowShowWallpaper を追加することができないため Android の設定を直接書き換える Plugin を作成して動的に styles に項目を追加したいと思います。

https://docs.expo.dev/config-plugins/plugins-and-mods/
https://docs.expo.dev/modules/config-plugin-and-native-module-tutorial/

ドキュメント内で expo-module-scripts 使うと簡単にできるよーと記載があるため、そちらの手順に従って進めたいと思います。

https://github.com/expo/expo/tree/main/packages/expo-module-scripts#-config-plugin

まずはプロジェクトに expo-module-scripts をインストールします。

yarn add -D expo-module-scripts
# or
npm install --save-dev expo-module-scripts

手順に従いつつ、今回は必要最低限のファイルだけ追加していきます。

test/ ・・・ プロジェクトルート
  app.plugin.js ・・・ プラグイン import 用
  plugin/ ・・・ プラグインディレクトリ
      tsconfig.json ・・・ TypeScript 用 config ファイル
      src/index.ts ・・・ プラグインコード
app.plugin.js
module.exports = require('./plugin/build');
plugin/tsconfig.json
{
  "extends": "expo-module-scripts/tsconfig.plugin",
  "compilerOptions": {
    "outDir": "build",
    "rootDir": "src"
  },
  "include": ["./src"],
  "exclude": ["**/__mocks__/*", "**/__tests__/*"]
}

styles に windowShowWallpaper を追加するコードを記載します。

plugin/src/index.ts
import { AndroidConfig, ConfigPlugin, withAndroidStyles } from 'expo/config-plugins';

const withAndroidConfigure: ConfigPlugin = config => {
    return withAndroidStyles(config, (config) => {
        config.modResults = AndroidConfig.Styles.assignStylesValue(config.modResults, {
            add: true,
            parent: AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(),
            name: "android:windowShowWallpaper",
            value: "true"
        });
        return config;
    });
};

export default withAndroidConfigure;

準備完了です。plugin をビルドします。待ち受け状態になるようなので少したったら強制終了します。

npx expo-module build plugin

ビルド後 watchman を停止しておきます。

watchman shutdown-server

app.json に plugin を追加します。

app.json
{
   "expo": {
       ...
+      "plugins": [
+        "./app.plugin.js"
+      ]
   }
}

改めて Android 版の Expo クライアントをビルドすると styles に設定が追加されるようになりました。

/android/app/src/main/res/values/styles.xml
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:windowBackground">@color/activityBackground</item>
+   <item name="android:windowShowWallpaper">true</item>
  </style>

これでアプリの背景にシステムで設定されている壁紙が表示されるようになりました🎉

Discussion