지금까지 몇 차례 「AI 에이전트(Claude Code)가 모바일 앱을 조작한다」는 측면의 검증 기사를 써왔다. 이번에는 반대 방향으로, 모바일 앱 자체에 OS 순정 온디바이스 AI(LLM)를 내장하면 어떻게 되는지를 시도해 보았다.
iOS에는 Foundation Models 프레임워크(Apple Intelligence), Android에는 Gemini Nano(ML Kit GenAI/AICore)라는, 각 OS가 보유한 온디바이스 LLM이 있다. flutter_gemma_builtin_ai라는 Flutter 패키지를 사용하면 이 두 가지를 동일한 Dart API로 나누어 호출할 수 있다고 한다. 실제로 iOS/Android 양쪽에서 실행하여 어디까지 '크로스 플랫폼(Cross-platform)'인지 확인했다.
검증 환경: Flutter 3.44.4. macOS 26.5 / Apple M5 (Apple Silicon). iOS 시뮬레이터(iPhone 17 Pro, iOS 26.5). Android 에뮬레이터(Pixel 10 Pro XL AVD) 및 Android 실기기(Xiaomi Redmi, Android 16). flutter_gemma 1.4.2 / flutter_gemma_builtin_ai 0.1.0.
Flutter 앱을 작성하기 전에, 애초에 이 머신에서 Apple 순정 온디바이스 LLM이 동작하는지 swift 명령어로 직접 확인해 보았다.
import FoundationModels
let model = SystemLanguageModel.default
print("availability: \(model.availability)")
...
실행 결과(실제 출력):
availability: available
RESPONSE: こんにちは!
Apple Silicon 머신에서 일본어 프롬프트에 대해 온디바이스로(네트워크 불필요) 실제로 응답이 돌아왔다. 이를 확인한 후 Flutter 앱 구현으로 넘어갔다.
flutter_gemma 본체는 Gemma 모델을 번들/다운로드하여 실행하는 패키지이지만, flutter_gemma_builtin_ai는 OS가 처음부터 가지고 있는 모델을 사용한다. 모델 파일의 다운로드가 필요 없는 「OS의 기능을 활성화할 뿐」이라는 위치를 차지한다.
void main() {
WidgetsFlutterBinding.ensureInitialized();
FlutterGemma.initialize(
...
플랫폼에 따라 모델 지정만 바꾸면 이후 코드는 공통:
final spec = defaultTargetPlatform == TargetPlatform.android
? BuiltInAiModels.geminiNano
: BuiltInAiModels.appleFoundationModels;
...
「Availability 확인」 버튼과 「프롬프트 실행」 버튼만 있는 심플한 검증 앱을 만들었다.
- iOS:
flutter run이 Target Integrity (Xcode): The package product 'flutter-gemma' requires minimum platform version 16.0 for the iOS platform, but this target supports 13.0로 실패. 기본값인 IPHONEOS_DEPLOYMENT_TARGET = 13.0을 16.0으로 올려 해결.
- Android: 패키지 README에 「Consumer apps require minSdk 26」이라고 명시되어 있었으므로,
minSdk를 26으로 고정.
「Availability 확인」을 탭.
status: BuiltInAiAvailability.available
이어서 「프롬프트 실행」. 실제로 Apple Foundation Models가 생성한 응답이 앱 내에 표시되었다.
response: TextResponse("こんにちは!")
(LLM의 출력물이므로, 동일한 프롬프트라도 실행할 때마다 문구는 달라질 수 있다. 여기에 기재한 것은 실제로 얻은 1회분의 출력이다.)
시뮬레이터는 호스트 Mac의 실행 환경을 그대로 사용하기 때문에, Apple Silicon이면서 Apple Intelligence가 활성화된 Mac 상이라면 실제 iPhone 기기를 준비하지 않아도 Foundation Models의 동작을 확인할 수 있었다. 또한 flutter_gemma_builtin_ai의 README에 따르면, 실제 기기에서 동일한 기능을 사용하려면 iPhone 15 Pro 이후 모델이면서 Apple Intelligence가 활성화되어 있어야 하며, 이 역시 무조건 작동하는 것은 아니다.
동일한 코드 상태에서 「Availability 확인」을 탭한다.
status: BuiltInAiAvailability.unavailableDeviceUnsupported
flutter_gemma_builtin_ai의 README에는 "Gemini Nano(AICore)는 Pixel 9+ / Galaxy S25+ 실제 기기가 필요하다"라고 적혀 있다. AVD(소프트웨어 에뮬레이터)에는 AICore를 담당하는 전용 칩이 없으므로, 이는 예상했던 결과였다. 이어서 「프롬프트 실행」을 탭하자, ensureReady()가 예외(Exception)를 던졌고 이를 캐치했다.
response: ERROR: BuiltInAiUnavailableException(BuiltInAiAvailability.unavailableDeviceUnsupported): Built-in AI is not available: BuiltInAiAvailability.unavailableDeviceUnsupported
크래시(Crash)나 무한 대기에 빠지지 않고, 타입이 지정된 예외로서 명확하게 실패하도록 설계되어 있었다.
"에뮬레이터라서 작동하지 않는 것뿐 아닌가?"라는 의문이 남기에, 수중에 있던 Android 실제 기기(Xiaomi Redmi, Android 16)에서도 동일한 앱을 실행해 보았다. 이 단말기는 Pixel 9+도 Galaxy S25+도 아니다.
status: BuiltInAiAvailability.unavailableDeviceUnsupported
결과는 에뮬레이터와 동일한 unavailableDeviceUnsupported였다. 「프롬프트 실행」에서도 동일한 BuiltInAiUnavailableException이 던져졌다. 즉, "에뮬레이터라서 작동하지 않는 것"이 아니라, AICore를 지원하지 않는 실제 기기에서도 마찬가지로 차단된다는 것을 확인할 수 있었다. 반대로 Pixel 9+ / Galaxy S25+와 같은 AICore 지원 실제 기기라면 작동할 것이나, 해당 기기는 수중에 없어 확인하지 못했으며 README의 기재 내용을 근거로 삼는다.
통합 Dart API를 통해 OS 순정 온디바이스 LLM을 호출하는 코드는 iOS/Android 공통으로 작성할 수 있었다. 실제로 분기되는 부분은 사용 모델을 지정하는 단 한 줄뿐이다. -
iOS(Apple Silicon Mac 상의 시뮬레이터)는 실제로 작동했다. availability()가 available을 반환하였고, 실제로 일본어 응답을 온디바이스에서 생성할 수 있었다. -
Android는 에뮬레이터에서도, Gemini Nano를 지원하지 않는 실제 기기에서도 작동하지 않는다. Gemini Nano(AICore)는 Pixel 9+ / Galaxy S25+급의 전용 하드웨어가 필요하며, AVD뿐만 아니라 수중의 Android 실제 기기(Xiaomi Redmi)에서도 unavailableDeviceUnsupported라는 동일한 타입의 에러가 발생했다. "실제 기기라면 작동한다"는 뜻이 아니다. -
"크로스 플랫폼(Cross-platform)으로 작성할 수 있는 것"과 "크로스 플랫폼에서 작동하는 것"은 별개이며, OS 및 실제 기기의 하드웨어 요구 사항에 따라 실제 동작은 크게 비대칭적일 수 있다는 실례였다.