배경:

테스트폰을 18.2 버전으로 업데이트 한 뒤, 잊고있었다가 똑같은 코드로 xcode로 앱을 실행시켰는데 흰 화면이 나타남.

 

증상:

플러터 기존 앱 코드를 실행했을 때, 안드로이드는 정상작동.

하지만 iOS 기기에서만 웹뷰가 처음 로드될 때 흰 화면이 나타남.

앱 실행 - 홈탭의 웹뷰가 onWebViewCreated 까지만 실행 - 흰 화면 - 다른 탭은 정상 연결 

 

로그:

Warning: -[BETextInput attributedMarkedText] is unimplemented

nw_application_id_create_self NECP_CLIENT_ACTION_GET_SIGNED_CLIENT_ID [80: Authentication error]

Failed to resolve host network app id

Invalidating grant <invalid NS/CF object> failed

Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "((target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.rendering AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.networking AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.webcontent))" UserInfo={NSLocalizedFailureReason=((target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.rendering AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.networking AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.webcontent))}>

 

이런 경고 로그가 자꾸 나타남..

결과적으론 저 로그는 별 의미가 없긴했지만.

 

히스토리:

 

  1. Info.plist 수정
  2. Entitlements 수정
  3. Singletone 수정
  4. 웹뷰 로드 타이밍 수정
  5. Url 수정 테스트
  6. Domain exception 추가
  7. Capability 추가 수정
  8. InAppWebView 설정 수정
  9. Xcode 업데이트
  10. Firebase app name 일치 테스트
  11. Flutter clear, pub get 시도
  12. iOS 캐시 삭제 재시작 시도
  13. 웹뷰 init 완료된 직접 url 연결
  14. Flutter 업데이트

위와 같은 삽질을 했다.. 

기존에 작성한 글은 그대로 남겨둔다.

 

2025 Feb 10 

: 구글링해서 에러를 해결하기 위한 단서들을 찾았지만 별 의미 없었음

 

1. 

https://github.com/apache/cordova-ios/issues/1440

 

IOS report "Failed to resolve host network app id" error, Android is working properly · Issue #1440 · apache/cordova-ios

Bug Report Problem The Android platform app is working normally, and then we added the iOS platform. When running in the emulator, a white screen appears and the console reports "Failed to resolve ...

github.com

 

 

2.

https://developer.apple.com/forums/thread/762223?answerId=812340022#812340022

 

WKWebView can't connect to externa… | Apple Developer Forums

Finally solved: it turned out I just needed to set the 'customUserAgent' property of the WKWebView. It's not clear why this wasn't required in iOS versions prior to iOS 17.5, but in any case the behavior seems to be working correctly again with this fix!

developer.apple.com

 

InAppWebView 설정에서 다음 코드 추가

userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/605.1.15",

 

 

그런데 2번은 내겐 아무 의미가 없었다.

아직 해결하지 못해서 기록차원에서 작성

 

하.. 안드로이드는 참 잘되는데... 아이폰.....

 

 

---------

 

2025 Feb 11

: 드디어 원인을 발견했다.

iOS를 18.2 로 업데이트 해서 이전 버전의 Flutter 혹은 패키지들과 호환 오류가 발생함.

 

원인을 발견한 계기는 다음 코드를 실행.

...

onWebViewCreated: (controller) {
    // 여기에서 강제로 url 로드
    controller.loadUrl(
        urlRequest: URLRequest(url: WebUri("https://www.google.co.kr"))
    );
 },
 
 ...

 

 

이렇게 했더니 웹뷰에 탭 이벤트가 안 먹혔다.

화면은 나타나지만 탭이 안 되는 상황... 그렇게 검색했더니 드디어 정확한 원인을 확인했다..!

 

https://github.com/pichillilorenzo/flutter_inappwebview/issues/2415

 

Tap interactions not working on iOS 18.2 · Issue #2415 · pichillilorenzo/flutter_inappwebview

Is there an existing issue for this? I have searched the existing issues Current Behavior Once I interact with any widget in the application that isn't the web view, the webview stops recognizing a...

github.com

 

InAppWebView 제작자의 예제 코드:

https://github.com/flutter/flutter/issues/159911#issuecomment-2539973403

 

[CP][For 3.28 and NOT 3.27!!!][ios][platform_view] workaround for non-tappable webview · Issue #159911 · flutter/flutter

Issue Link flutter/engine#57030 Target beta Cherry pick PR Link flutter/engine#57032 Changelog Description Fix an issue on iOS 18.2 where web view's link is not tappable. Impacted Users all end cus...

github.com

 

 

해결방법 :

 

1. 흰화면 오류 해결 / whiteScreen :

 

만약 웹뷰 설정시 다음 값을 사용하고있는지 확인하자.

useShouldOverrideUrlLoading: true,

 

 

값이 true 일 때 웹뷰 구현코드에 "shouldOverrideUrlLoading"이 작성되어있어야 했다.

 

@override
Widget build(BuildContext context) {
return Scaffold(
        appBar: AppBar(title: const Text("Example")),
        body: SafeArea(
        child: Column(children: <Widget>[
        Expanded(
                child: Stack(
                  children: [
                    InAppWebView(
                      key: webViewKey,
                      initialUrlRequest:
                      URLRequest(url: WebUri("https://flutter.dev/")),
                      initialSettings:
                      InAppWebViewSettings(isInspectable: kDebugMode),
                      onWebViewCreated: (controller) {
                        webViewController = controller;
                      },
                      onLoadStart: (controller, url) {
                        setState(() {
                          this.url = url.toString();
                          urlController.text = this.url;
                        });
                      },
                      onLoadStop: (controller, url) async {
                        setState(() {
                          this.url = url.toString();
                          urlController.text = this.url;
                        });
                      },
                      // 여기서부터 필요한 코드
                      shouldOverrideUrlLoading: (controller, navigationAction) {
                        return NavigationActionPolicy.ALLOW;
                      },
                      ...

 

만약 사용중이라면?

저 코드때문에 iOS 기기에서 흰화면 오류가 발생한다.

 

저 코드가 원인이었던 것!!!!!!

 

하지만 나는 android에서는 저 코드가 필요했기때문에 다음과 같이 수정했다.

 

shouldOverrideUrlLoading: Platform.isAndroid ?
    (controller, navigationAction) async {
  var uri = navigationAction.request.url!;
  // 기존 코드
  return NavigationActionPolicy.ALLOW;
} : null,

 

이러면 문제 해결 !

 

 

iOS 업데이트 할때마다 참 즐겁다..

 

 

 

2. 웹뷰에서 터치 오류 해결:

 

- Flutter Upgrade 3.27.4

https://flutter-ko.dev/development/tools/sdk/releases

 

Flutter SDK archive

All current Flutter SDK releases: stable, beta, and main.

docs.flutter.dev

 

- Xcode Upgrade 16.2

 

 

Xcode 16.2 버전부터 iOS 18.2 버전 케어하니까 업데이트를 해주자..


에러 배경:

 

Flutter Flavor 를 통해 앱을 Dev, Prod 모드로 분리시켜서 빌드 시키기 위해 개발을 하고있었다.

Xcode에서 Debug-Dev, Debug-Prod, Release-Dev, Release-Prod, Profile-Dev, Profile-Prod 로 configurations 생성하고 스키마도 추가해서 알맞게 적용까지 완료.

기존에 있었던 파이어베이스도 잘 분리시켜서 적용해서 Xcode로 빌드까지 성공했다.

 

그런데 Xcode로 빌드한 앱이 기기에서 그냥 실행하면 크래시가 발생했다.

 

에러:

Terminal로 연결해서 빌드해도 잘 되고 Xcode로 연결해서 빌드해도 문제 없이 잘 작동되던 앱이

기기에서 실행만 하면 크래시가 발생하는 현상 발생. 

빌드하지 않고 기기에서 앱을 실행하면 앱이 터진다.

 

콘솔로 확인한 에러 메시지:

 

[ERROR:flutter/runtime/ptrace_check.cc(75)] Could not call ptrace(PT_TRACE_ME): Operation not permitted

Cannot create a FlutterEngine instance in debug mode without Flutter tooling or Xcode.

 

To launch in debug mode in iOS 14+, run flutter run from Flutter tools, run from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.

 

Alternatively profile and release mode apps can be launched from the home screen.

 

 

최근 Xcode를 15로 업데이트 했더니 이런 새로운 이슈가 발생했다. ㅎㅎ 즐거운 iOS 앱개발..

 

 

원인: 

configuration이 Debug 로 선택되어있으면 기기에서 앱을 단독으로 실행시킬 때 권한이 없어서 크래시가 발생한다.

즉, 빌드할때 사용하는 configuration을 Release 로 설정해야한다.

 

 

해결방안:

 

 

1. 빌드할때 사용하는 스키마를 선택 - Edit Scheme 클릭

 

 

2. 앱을 빌드할때 사용하는 configurations를 수정하자.

Run - Info - Build Configuration - Release 

 

 

 

이렇게 빌드하면 Xcode와 터미널로 실행하지 않아도 기기에서 앱이 제대로 실행된다.

 

별 것 아닌 이유로 오랜 시간을 허비했다... ㅠ

 

FCM 구현은 잘 적힌 글이 많으니 생략하겠습니다.

 

- 구현하고싶은 알림 화면 ( Heads-up ) push notification image

 

구현하는데 애먹은 부분은 안드로이드에서 FCM 을 받았을때

앱이 종료/비활성화 일때 다음과 같이 배너 알림 (혹은 heads-up 알림) 띄우기였습니다.

 

결론부터 말하자면 해결책은 백엔드에 있다!!

 

 

다음은 구글에서 안내하는 서버 알림 예제입니다.

https://firebase.google.com/docs/cloud-messaging/migrate-v1?_gl=1*14deht6*_up*MQ..*_ga*MjA1NTg3NzcwNS4xNzI4MzU0MjAz*_ga_CW55HF8NVT*MTcyODM1NDIwMy4xLjAuMTcyODM1NDIyMC4wLjAuMA..

 

기존 HTTP에서 HTTP v1로 마이그레이션  |  Firebase Cloud Messaging

의견 보내기 기존 HTTP에서 HTTP v1로 마이그레이션 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. FCM의 기존 HTTP API를 사용하는 앱은 이 가이드의 안내에 따라

firebase.google.com

 

 

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY",
        "body": "Check out the Top Story"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

 

위와 같이 예제를 따라 서버단에서 FCM 에 전송할 json을 구현했다고 가정하면,

flutter 단에서는 해당 데이터를 받아 패키지나 firebase 함수를 통해 메시지를 화면에 띄워줍니다.

 

 

 

Flutter단에서 필요한 작업 :

 

1. AndroidManifest.xml 

<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="high_importance_channel"
    />

 

 

2. FlutterLocalNotificationPlugin 설정 

    final NotificationDetails notiDetail = const NotificationDetails(
      android: AndroidNotificationDetails(
        'high_importance_channel',
        'High Importance Notifications',
        importance: Importance.high,
        priority: Priority.high,
        playSound: true,
        enableVibration: true,
        icon: "mipmap/m_logo",
      ),
      iOS: DarwinNotificationDetails(
        presentAlert: true,
        presentBadge: true,
        presentSound: true,
        presentBanner: true,
      ),
    );

      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
          ?.createNotificationChannel(
          const AndroidNotificationChannel(
            'high_importance_channel', // id
            'High Importance Notifications', // title
            description:
            'This channel is used for important notifications.', // description
            importance: Importance.high,
            showBadge: true,
          )
      );

 

 

백엔드에서 해주어야할 작업:

 

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
    "priority": "high", // 코드 추가
      "notification": {
      	"channel_id": "high_importance_channel", // 코드 추가
        "click_action": "TOP_STORY_ACTIVITY",
        "body": "Check out the Top Story"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

 

 

'// 코드 추가' 주석을 달아놓은 줄을 추가해주면 된다.

 

메시지를 전달할때 안드로이드에서 priority와 channel_id 를 추가하는 것이 중요!

 

iOS 에서는 잘 되는데 안드로이드에서는 인앱웹뷰를 통해 만든 웹뷰 화면에서 다운로드 링크를 눌렀을 경우,

아무 일도 일어나지 않는다.

 

그래서 찾은 가장 쉬운 해결방법!

 

1. 패키지를 다운받는다. 

그런데 InAppWebView를 사용하려면 받아두었을지도?

 

https://pub.dev/packages/url_launcher

 

url_launcher | Flutter package

Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes.

pub.dev

 

 

2. AndroidManifest.xml에 다음 코드 추가

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

 

 

 

3. 다운로드 요청을 잡아서 수동으로 처리


child: InAppWebView(
                  key: webViewKey,
                  initialUrlRequest: URLRequest(url: WebUri(initUrl)),
                  onWebViewCreated: (controller) {
                    webController = controller;
                  },
                  
                  ...
                  
                  // 하기 코드 추가

                  onDownloadStartRequest: (controller, downloadRequest) async {
                    String downloadUrl = downloadRequest.url.toString();

                    if (Platform.isAndroid) {
                      if (await canLaunchUrl(WebUri(downloadUrl))) {
                        await launchUrl(WebUri(downloadUrl));
                      } else {
                        throw 'Could not launch $downloadUrl';
                      }
                    }

                  },
                  
                  ...

 

 

이렇게 처리하면 번거롭게 다른 패키지들을 설치하지 않아도 다운로드가 된다.

 

 

 

플러터 웹뷰를 사용중에 화면을 당겨서 웹페이지 새로고침을 하는 기능이 있다.

이때, 새로고침이 완료되었음에도 상단에서 로딩 아이콘이 계속 돌아가는 이슈 해결 방법을 공유한다.

 

  void initState() {
    super.initState();

    pullToRefreshController = kIsWeb
        ? null
        : PullToRefreshController(
      settings: PullToRefreshSettings(
        color: Colors.black,
      ),
      onRefresh: () async {
        if (Platform.isAndroid) {
          webController?.reload();
        } else if (Platform.isIOS) {
          webController?.loadUrl(
            urlRequest:
            URLRequest(
              url: await webController?.getUrl()),
          );
        }

        pullToRefreshController?.endRefreshing(); // 이 코드 추가
      },
    );
  }

 

 

앱을 배포하기 위해 아카이빙을 진행하는 도중 xcode 에서 에러가 발생했다.

 

CFBundleIconFiles is not of the required type for that key 해결방법

 

flutter clean? flutter build ios? 다 필요없다.

 

xcode에서 info.plist 오픈.

 

info.plist를 IDE에서 열지 말고 directory단에서 텍스트 편집기로 열 것!!

 

1.

CFBundleIconFiles 검색해서 하단 <String></String> 태그까지 싹 삭제

 

2. 

info.plist 저장한 뒤 다시 Archive.

이 때, 프로젝트를 한번이라도 실행시킬 경우 다시 키 값이 생성되므로 주의!

 

이러면 해결된다.

 

 

 

에러코드:

E/MethodChannel#.com/flutter/local_notifications( 7674): Failed to handle method call
E/MethodChannel#.com/flutter/local_notifications( 7674): java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
E/MethodChannel#.com/flutter/local_notifications( 7674):  at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.setSmallIcon(FlutterLocalNotificationsPlugin.java:76)
E/MethodChannel#.com/flutter/local_notifications( 7674):  at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:88)

 

flutter app android error 

FlutterLocalNotificationsPlugin.setSmallIcon

 

안드로이드에서 FlutterLocalNotificationsPlugin을 통해 내부 알림을 보낼 때 나타나는 icon 설정이 잘못되어있기 때문에 이미지를 찾을 수 없어 알림이 안 나오는 에러!

 

따라서 icon 이미지만 지정해주면 해결된다:

 

FlutterLocalNotificationsPlugin().show(
  notification.hashCode,
  notification.title,
  notification.body,
  const NotificationDetails(
    android: AndroidNotificationDetails(
      'high_importance_channel',
      'High Importance Notifications',
      importance: Importance.max,
      playSound: true,
      enableVibration: true,
      icon: "mipmap/app_icon", //당신의 mipmap 폴더에 있는 보여주려는 아이콘 파일명 입력. 확장자 필요없음
    ),
    iOS: DarwinNotificationDetails(
      presentAlert: true,
      presentBadge: true,
      presentSound: true,
      presentBanner: true,
    ),
  ),
);

 

flutter 앱에서 SafeArea 배경화면이 흰색이라 아이콘이 보이지 않을때,

background를 색칠해줄 수 있다.

 

@override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black, //이 부분
      body: SafeArea(
        child: Container(
          decoration: const BoxDecoration(
            image: const DecorationImage(
              image: AssetImage('assets/images/my_bg.png'),
              fit: BoxFit.cover,
            ),
          ),
          child: ...

 

ios에 Splash image 하나를 추가했을 뿐인데 갑자기 

아이폰에서 Splash Screen 에 멈춰서 아무 동작이 안되기 시작했다...

 

지난번에 이 오류를 고치지 못해서 꽤나 애먹었는데 해결책을 찾아 공유한다.

 

https://github.com/jonbhanson/flutter_native_splash/issues/577#issuecomment-1841518637

 

flutter iOS app is stuck on launchscreen when installed on real device · Issue #577 · jonbhanson/flutter_native_splash

Describe the bug I have this flutter app where I've set up a flutter_native_splash screen with the package that is named the same. I've used the command and the description from the installation gu...

github.com

 

Thanks a lot, https://github.com/gikwegbu !!

 

 

플러터 앱 실행이 잘 되다가 갑자기 iOS만 하얀 화면 혹은 스플래시 화면에 멈춰있는 경우,

 

token = await _firebaseMessaging.getToken();

 

이 녀석이 에러의 원인이었다.

ios 에서는 token이 아니라 APNS Token을 받아오는데 그걸 처리해주지 않아서 무한 로딩에 걸리는 것이다...

 

 

 

flutter No file or variants found for asset  에러

플러터에서 이미지 로딩이 안 될 경우

 

flutter:
  assets:
    - assets/images/

 

 

pubspec.yaml 파일에 assets 폴더를 인식할 수 있도록 작성.

그 때 모든 이미지 파일을 나열해서 작성하지 않고 그냥 이미지 폴더까지 등록해도 인식 가능

 

위와 같이 수정 후,

프로젝트 디렉토리에서 flutter clean 해준다.

 

만약 ios도 함께 개발중이라면 project directory 에서 flutter clean 완료된 후 flutter build ios도 실행

% flutter clean 
% flutter build ios

+ Recent posts