対象読者:
- Expo(React Native)でAndroidアプリを開発しており、画面下部の「ナビゲーションバー(システムバー)」を非表示にしたい方。
NavigationBar.setVisibilityAsync is deprecatedやCannot find native module 'ExpoNavigationBar'のエラーで詰まっている方。
この記事でわかること
- Expo SDK 54以降でAndroidの「edge-to-edge」表示が強制になった背景
expo-navigation-barの非推奨API(setVisibilityAsync/setBehaviorAsync)と新しい書き方Cannot find native module 'ExpoNavigationBar'エラーの原因と解決策- 実際に手を動かして解決するまでの手順
なぜ今までのやり方が使えなくなったのか?
Expo SDK 54(React Native 0.81)から、Android 16をターゲットにしたことで edge-to-edge(画面端から端までの表示)がすべてのAndroidアプリで強制されるようになりました。これはOSレベルの仕様変更であり、アプリ側で無効化することはできません。
この変更に伴い、expo-navigation-bar パッケージの多くのAPIが 「no-op(呼び出しても何も起きない)」化 されました。具体的には以下のメソッドです。
setBackgroundColorAsyncsetBorderColorAsyncsetBehaviorAsyncsetPositionAsyncsetButtonStyleAsync
これらは「ナビゲーションバーの背景色」や「スワイプ時の挙動」を細かく制御するためのAPIでしたが、edge-to-edgeが標準になったことで意味を持たなくなり、非推奨(Deprecated)となっています。
新しいAPI:NavigationBar コンポーネントと setHidden
現在の expo-navigation-bar では、表示・非表示の制御は以下のどちらかの方法で行います。
方法1:コンポーネントで宣言的に指定する(推奨)
TypeScript
import { NavigationBar } from "expo-navigation-bar";
export default function App() {
return (
<>
<NavigationBar hidden={true} />
{/* アプリ本体 */}
</>
);
}
方法2:命令的に呼び出す
TypeScript
import { useEffect } from "react";
import { NavigationBar } from "expo-navigation-bar";
export default function App() {
useEffect(() => {
NavigationBar.setHidden(true);
}, []);
return (
// アプリ本体
);
}
[!CAUTION]
setVisibilityAsync("hidden")のような旧APIは今後のバージョンで削除される予定です。新規実装では上記の書き方に統一しておくのが安全です。
ビルド時に固定したい場合(config plugin)
実行時ではなく、ビルドの段階で挙動を固定したい場合は app.json に config plugin を追加します。
JSON
{
"expo": {
"plugins": [
["expo-navigation-bar", { "hidden": true }]
]
}
}
※この設定を反映するには、後述する prebuild によるネイティブコードの再生成が必要です。
「Cannot find native module ‘ExpoNavigationBar’」の原因と対処法
expo-navigation-bar を導入してコードを書き換えたのに、実機やエミュレータで以下のエラーが出るケースがあります。
Plaintext
Error: Cannot find native module 'ExpoNavigationBar'
これは非常によくあるハマりポイントで、原因は大きく2つあります。
原因1:Expo Goで実行している
expo-navigation-bar はネイティブコードを含むモジュールのため、ストア版の Expo Goアプリでは動作しません。Development Build(expo-dev-client)でのみ利用可能です。
原因2:過去にビルドしたアプリ(バイナリ)をそのまま使っている
これが一番の盲点です。npm run start(expo start)は JavaScriptのバンドラを起動するだけ のコマンドであり、実機にインストール済みのネイティブアプリ自体を更新しません。
つまり、expo-navigation-bar を後から npm install しても、過去にビルドしたアプリのバイナリにはそのネイティブモジュールが組み込まれていません。そのため、JS側から呼び出そうとしても「ネイティブ側に実体がない」となりエラーになります。
解決策:ネイティブアプリを作り直す
ネイティブモジュールを追加・変更したときは、必ずアプリ本体を再ビルド・再インストールする必要があります。
ローカルで再ビルドする場合
Bash
npx expo prebuild --platform android --clean
npx expo run:android
EAS Buildを使っている場合
Bash
eas build --profile development --platform android
ビルドが完了したら、生成されたアプリを実機に入れ直してから、あらためて npm run start を実行してください。
[!TIP] 「JSコードの変更だけなら再ビルド不要、ネイティブモジュールが絡む変更は必ず再ビルドが必要」という原則を覚えておくと、今後の開発でもハマらなくなります。
まとめ:作業手順のチェックリスト
npx expo install expo-navigation-barでパッケージを追加する<NavigationBar hidden={true} />または config plugin で非表示設定を行うnpx expo prebuild --cleanでネイティブプロジェクトを再生成するnpx expo run:android(または EAS Build)でアプリを再ビルドし、実機に入れ直すnpm run startでMetroを起動し、動作確認する
この手順さえ踏めば、SDK 54以降のedge-to-edge環境でも問題なくナビゲーションバーを非表示にできます。
よくある質問(FAQ)
Q. iOSでも同じようにホームインジケーターを非表示にできますか?
A. できません。iOSでは通常のアプリに対してホームインジケーターの非表示は基本的に許可されておらず、ゲームなどの一部の例外を除いて、Expo公式からも同様の簡易APIは公開されていません。
Q. ナビゲーションバーを非表示にすると、ユーザーは操作できなくなりませんか?
A. 非表示にしても、画面端からスワイプすれば一時的にナビゲーションバーを呼び出せます。これはAndroid OS標準の挙動(Immersive Mode)で、アプリ側から変更することはできません。
Q. expo-navigation-bar はExpo Goで試せますか?
A. 試せません。ネイティブコードを含むため、Development Buildまたは本番ビルドでのみ動作します。


コメント