Flutterアプリを開発していると、実機とiOSシミュレーターで処理を分けたいケースがあります。
例えば、
- iOSシミュレーターでは特定の処理をスキップする
- 実機でのみ利用できる機能を制御する
- シミュレーターではテスト用データを利用する
- カメラやセンサーなどの実機依存機能を切り替える
- パッケージ内部でiOSシミュレーターを判定する
といった用途です。
Flutterにはプラットフォームを判定するためのAPIがありますが、iOSの実機なのかシミュレーターなのかをピンポイントで判定したい場合があります。
今回紹介する is_ios_simulator は、その名前の通り、アプリがiOSシミュレーター上で実行されているのか、それとも実機上で実行されているのかを判定するための小さなFlutterパッケージです。
現在のバージョンは 1.0.1 で、iOS専用のパッケージとして提供されています。
この記事では、is_ios_simulator の基本的な使い方から、実機・シミュレーターの判定、内部実装、条件分岐への利用方法まで詳しく解説します。
is_ios_simulatorとは?
is_ios_simulator は、Flutterアプリが iOSシミュレーターで実行されているかどうかを判定するためのパッケージです。
基本的には、
Flutterアプリ
↓
iOS環境を確認
↓
シミュレーター?
↙ ↘
Yes No
↓ ↓
true false
というシンプルな処理を行います。
パッケージのREADMEでは、isIosSimulator() がシミュレーター上では true、実機では false を返すAPIとして紹介されています。
is_ios_simulatorの特徴
主な特徴は以下の通りです。
| 機能 | 対応 |
|---|---|
| iOSシミュレーター判定 | ○ |
| iOS実機判定 | ○ |
| 非iOS環境での利用 | ○ |
| Webビルドへの配慮 | ○ |
| Conditional Import | ○ |
| 非同期API | ○ |
| 軽量な構成 | ○ |
| Android向け機能 | × |
| Windows向け機能 | × |
| macOS向け機能 | × |
このパッケージは、幅広いデバイス情報を取得するのではなく、iOSシミュレーターの判定だけに機能を絞っている点が特徴です。
インストール
pubspec.yaml に追加します。
YAML
dependencies:
is_ios_simulator: ^1.0.1
または、以下のコマンドでも追加できます。
Bash
flutter pub add is_ios_simulator
コードから利用する場合は、
Dart
import 'package:is_ios_simulator/is_ios_simulator.dart';
を追加します。
iOSシミュレーターか判定する
基本的な使い方は非常にシンプルです。
Dart
import 'package:is_ios_simulator/is_ios_simulator.dart';
final result = await isIosSimulator();
print(result);
isIosSimulator() は Future<bool> を返します。
iOSシミュレーター上で実行されている場合は、
true
実機では、
false
となります。
実機とシミュレーターで処理を分ける
取得した結果を利用すれば、実機とシミュレーターで処理を分けられます。
Dart
final isSimulator = await isIosSimulator();
if (isSimulator) {
print('Running on iOS Simulator');
} else {
print('Running on physical device');
}
例えば、シミュレーターでは実行できない処理をスキップできます。
Dart
final isSimulator = await isIosSimulator();
if (!isSimulator) {
await initializeHardwareFeature();
}
このようにすれば、実機でのみ特定の初期化処理を実行できます。
アプリ起動時に判定する
アプリ起動時に判定して、その結果を状態として保持することもできます。
Dart
Future<bool> checkSimulator() async {
return await isIosSimulator();
}
例えば、
Dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final isSimulator = await isIosSimulator();
runApp(
MyApp(
isSimulator: isSimulator,
),
);
}
のように、アプリ全体へ判定結果を渡すこともできます。
シミュレーターではテスト用データを使う
iOSシミュレーターでは、実機と同じ環境を再現できない機能があります。
そのような場合には、シミュレーターでテスト用データを利用できます。
Dart
final isSimulator = await isIosSimulator();
final userId = isSimulator
? 'test-user'
: await loadRealUserId();
開発環境での動作確認をしやすくできます。
カメラ機能の制御
カメラなど、実機での利用を前提とする機能を扱う場合にも利用できます。
例えば、
Dart
final isSimulator = await isIosSimulator();
if (isSimulator) {
showSimulatorWarning();
return;
}
await openCamera();
このようにシミュレーターではカメラ機能を利用せず、代わりにテスト用画面を表示できます。
センサー機能の制御
加速度センサーやその他のハードウェア機能でも、シミュレーターと実機で挙動が異なる場合があります。
例えば、
Dart
final isSimulator = await isIosSimulator();
if (isSimulator) {
return useMockSensorData();
}
return useRealSensorData();
といった構成にできます。
Webビルドにも配慮されている
is_ios_simulator の特徴の一つが、Conditional Importを利用していることです。
READMEでは、Conditional ImportによってWebビルドを壊さず、非iOSプラットフォームでは false を返す仕組みが説明されています。
そのため、パッケージを利用するコード側でiOS専用のネイティブAPIを直接扱う必要がありません。
非iOS環境ではfalse
このパッケージはiOSシミュレーターの検出が目的ですが、非iOS環境でも扱えるように設計されています。
READMEでは、非iOSプラットフォームでは false を返すとされています。
例えば、
iOS Simulator
↓
true
iOS Device
↓
false
Android
↓
false
Web
↓
false
という扱いになります。
これにより、Flutterのマルチプラットフォームプロジェクトでも条件分岐に利用できます。
IosSimulatorDetectionを直接利用する
通常はトップレベル関数の isIosSimulator() を利用しますが、内部で利用されている IosSimulatorDetection クラスを直接利用するAPIも提供されています。
Dart
final detection = IosSimulatorDetection();
final result = await detection.isIosSimulator();
print(result);
READMEでも、このAPIは isIosSimulator() の内部で利用される代替APIとして紹介されています。
通常のアプリ開発では、シンプルなトップレベル関数を利用する方法が分かりやすいでしょう。
なぜ専用パッケージを使うのか?
Flutterにはデバイス情報を取得するためのパッケージが存在します。
例えば、より広範囲なデバイス情報を取得するライブラリを利用して、その中からシミュレーターかどうかを確認する方法もあります。
しかし、単純に「iOSシミュレーターかどうか」だけを知りたい場合、より大きなパッケージを追加する必要はありません。
is_ios_simulator は、この用途に機能を絞っています。
パッケージのMotivationでも、device_info_plus のような幅広いデバイス情報パッケージを利用すると、不要な推移依存関係が追加される可能性があることが説明されています。
そのため、
デバイス情報を大量に取得したい
↓
device_info系
iOSシミュレーターだけ判定したい
↓
is_ios_simulator
という使い分けができます。
Flutterパッケージ開発にも利用できる
このパッケージは通常のFlutterアプリだけでなく、Flutterパッケージを開発するときにも役立ちます。
例えば、パッケージ内部でiOSシミュレーターと実機の処理を分けたい場合です。
final isSimulator = await isIosSimulator();
if (isSimulator) {
// Simulator-specific behavior
} else {
// Physical-device behavior
}
特に、公開パッケージでは不要な依存関係を増やしたくない場合があります。
そのようなケースで、用途を限定した軽量な依存関係として利用できます。
内部ではSwiftで判定している
このパッケージでは、iOS側の実装にSwiftを利用しています。
判定には、
Swift
#if targetEnvironment(simulator)
return true
#else
return false
#endif
という仕組みが利用されています。
targetEnvironment(simulator) は、Swiftコンパイラーが現在のビルド対象がシミュレーター環境なのかどうかを判定するための仕組みです。
そのため、実際の端末情報を取得して推測するのではなく、iOS側のビルド環境を利用して判定しています。
実機とシミュレーターの違い
Flutter開発では、iOSシミュレーターは非常に便利です。
しかし、すべての機能を完全に再現できるわけではありません。
例えば、
Flutter UI
↓
iOS Simulator
では確認できても、
カメラ
GPS
Bluetooth
センサー
プッシュ通知
などは実機での検証が重要になります。
そのため、シミュレーターと実機で処理を切り替える必要があるアプリでは、is_ios_simulator が役立ちます。
テストコードで利用する
テスト時にもシミュレーター判定を利用できます。
例えば、
final isSimulator = await isIosSimulator();
if (isSimulator) {
// Mock
} else {
// Real implementation
}
のように、実機では実際の処理を利用し、シミュレーターではMockを利用する構成にできます。
注意点
iOS専用のパッケージ
このパッケージの目的はiOSシミュレーターの検出です。
Android Emulatorなど、他のプラットフォームのエミュレーター検出を行うためのパッケージではありません。
非iOSではシミュレーター判定にはならない
非iOSプラットフォームでは false が返るため、Android Emulatorなどを判定する用途には利用できません。
デバイス情報全般を取得するものではない
モデル名、OSバージョン、メモリ、CPUなどの詳細なデバイス情報を取得するパッケージではありません。
あくまで、
iOS Simulator?
↓
Yes / No
という判定に特化しています。
シミュレーターだから必ず機能が使えないとは限らない
シミュレーターでも利用できる機能は多くあります。
そのため、単純にすべての処理をシミュレーターで無効化するのではなく、実際に利用する機能ごとに必要性を判断することが重要です。
メリット
非常にシンプル
1つの目的に特化しているため、APIを覚えやすくなっています。
不要な依存関係を増やしにくい
幅広いデバイス情報ライブラリを導入せず、シミュレーター判定だけを追加できます。パッケージ側でもこの点が導入理由として説明されています。
Webビルドにも配慮
Conditional ImportによってWebビルドを壊さず、非iOS環境では false を返す設計になっています。
iOS側の仕組みを利用
Swiftの targetEnvironment(simulator) を利用しているため、iOSのビルド環境を直接判定できます。
パッケージ開発にも向いている
公開パッケージ内部でiOSシミュレーターと実機の挙動を分けたい場合にも利用できます。
まとめ
is_ios_simulator は、Flutterアプリが iOSシミュレーター上で動作しているかどうかを判定することに特化した軽量なパッケージです。
基本的な使い方は、
Dart
final result = await isIosSimulator();
だけなので非常にシンプルです。
主な特徴として、
- iOSシミュレーターを判定
- iOS実機を判定
- 非iOS環境では
false - Conditional Importに対応
- Swiftによるネイティブ判定
IosSimulatorDetectionAPIも利用可能- 不要なデバイス情報ライブラリを導入せずに済む
などが挙げられます。
特に、カメラやセンサーなど実機依存の機能を扱うアプリや、シミュレーターではMockを利用したいFlutterアプリ、そして不要な依存関係を増やしたくないFlutterパッケージの開発では便利でしょう。
「iOSシミュレーターかどうかだけ分かればいい」というケースでは、非常に分かりやすい選択肢となるパッケージです。
