728x90
반응형

 

Firebase Analytics 패키지를 사용하던 중 새로운 버전이 나와 버전 업데이트를 진행했습니다.

 

Debug모드에서는 전혀 문제가 없었지만 스토어 배포를 하던 중에 'com.google.android.gms.permission.AD_ID' 권한에 대한 오류가 발생했습니다.

 

기본적으로 AD_ID 권한이 존재 하지만 광고 ID를 사용하지 않아 Paly Console에서 '광고' 앱 콘텐츠를 수정해줘야 합니다.

[!] Google Api Error: Invalid request - This release includes the com.google.android.gms.permission.AD_ID permission but your declaration on Play Console says your app doesn't use advertising ID. You must update your advertising ID declaration.

 

 

 

 

# Analytics version 20.1.1 릴리즈에서 해당 내용이 추가 되었습니다.

 

# Android 12, 13 광고 ID 요구사항 입니다.

https://developers.google.com/interactive-media-ads/docs/sdks/android/dai/android-12

 

Android 12 and 13 targeting requirements  |  IMA DAI SDK for Android  |  Google Developers

Send feedback Android 12 and 13 targeting requirements Stay organized with collections Save and categorize content based on your preferences. Advertising ID If your app uses the IMA SDK version 3.25.1 or higher, the SDK already automatically declares the c

developers.google.com

 

 

 

 

# 콘텐츠 수정 

Google Play Console에 진입해줍니다.

https://play.google.com/console

 

Google Play Console | Google Play Console

앱 및 게임이 성장할 수 있도록 사용자에게 도달하고 사용자 참여를 유도하는 데 도움이 될 도구, 프로그램, 통계를 이용하세요.

play.google.com

 

 

 

개발자 계정을 선택하고, 수정할 앱을 선택합니다.

 

앱 상세에 들어가면 좌측 하단에 '정책 및 프로그램' 메뉴에서 '앱 콘텐츠' 메뉴로 진입합니다.

 

 

 

'광고 ID' 항목에서 관리를 선택합니다.

 

 

'앱에서 광고 ID를 사용하나요?' 항목에서 '' 를 선택하고 아래 애널리틱스를 체크 하고 저장합니다.

 

 

# 마무리

위 변경된 정책은 심사를 거치게 됩니다.

 

심사에서 승인되면 권한에 대한 오류가 해결됨을 확인할 수 있습니다.

728x90
반응형
728x90
반응형

 

현재 진행중인 프로젝트에서 웹페이지 url을 입력받아 Open Graph 정보를 표시하는 작업을 하려고 합니다.

 

카카오톡이나 소셜 sns를 사용할 때 url만 입력해도 이미지와 제목이 뜨는걸 보셨을꺼에요.

 

일반적으로 웹 페이지를 만들때 약속된 meta tag라고 할 수 있는데요, 이런걸 Open Graph 프로토콜이라고 합니다. 

 

https://ogp.me/

 

Open Graph protocol

The Open Graph protocol enables any web page to become a rich object in a social graph.

ogp.me

 

 

 

# og meta tag 확인

쿠팡을 기준으로 작업을 해보겠습니다.

 

쿠팡 사이트에 들어가서 맥북을 검색해 본 뒤 크롬 기준으로 [도구 더보기 -> 개발자 도구] 항목을 클릭합니다.

 

 

 

펼쳐진 개발자 도구에서 'Elements' 탭을 선택하면 HTML요소들어 보여집니다.

 

head tag부분에서 아래와같이 link, meta, script 태그들이 보이네요.

 

 

 

저는 여기서 og: 라고 시작되는 태그들만을 원합니다.

 

보통 다른 쇼핑몰 같은 경우에도 image, title, url, description 항목은 필수적으로 사용하고 있는데요.

 

이 정보들이 소셜 sns나 채팅에 공유될때 나오는 정보들입니다.

 

image - 상품의 이미지

title - 상품 제목

url - 해당 상품 url

description - 간략한 설명

 

 

 

 

# 개발 준비

 

Flutter 프레임워크에서는 특정 패키지가 필요합니다.

 

http 패키지로 사이트의 html문자열을 가져온 다음, html 패키지로 문자열을 html로 파싱파여 원하는 정보를 가져올겁니다.

https://pub.dev/packages/http

 

http | Dart Package

A composable, multi-platform, Future-based API for HTTP requests.

pub.dev

https://pub.dev/packages/html/install

 

html | Dart Package

APIs for parsing and manipulating HTML content outside the browser.

pub.dev

 

 

 

 

# 페이지 정보 읽기

아래처럼 패키지를 import 해줍니다.

import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parse;

 

 

http.get 함수로 웹페이지 주소를 넣어 호출합니다.

 

아래처럼만 작성해도 일반적인 사이트에서는 문제 없이 html 문자열을 응답받습니다.

final String uri = "웹 페이지 주소";
final response = await http.get(Uri.parse(uri));

 

 

 

하지만 쿠팡같은 경우에는 pending이 걸려버리고 response가 오지 않는것을 알 수 있습니다.

 

각종 블로그에서도 해당 문제에 대해서 다루지만 user-agent를 넣는 방법으로는 동작하지 않습니다.

 

 

 

 

해결을 위해 쿠팡 사이트에 들어와 다시 [도구 더보기 -> 개발자 도구] 로 진입해서 웹 페이지 요청 항목을 선택한 뒤 [Network -> Headers] 탭으로 들어가보겠습니다.

 

Request Headers 부분에서 아래와 같이 accept 정보를 넣어주어 압축된 정보를 주고받는걸 알 수 있는데요. 

 

 

 

 

저도 이와 같이 header정보를 추가 해주겠습니다.

 

그리고 만약 동작하지 않을 수 있다는 부분을 위해 timeout 시간을 2초로 주었습니다.

 

아래처럼 작성하시면 쿠팡 사이트의 정보까지 문제없이 html문자열을 응답받을 수 있습니다

final response = await http.get(Uri.parse(uri), headers: {
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
}).timeout(const Duration(seconds: 2));

 

 

 

# og tag 추출

이제 html문자열에서 og tag만 추출하면 되겠네요.

 

위에서 import한 alias를 확인해주시고 코드를 봐주시면 됩니다.

 

response.body에서 html 문자열만을 추출해 html로 변환하면 Document라는 객체로 변환됩니다.

 

이 Document 객체에서 어떻게 정보를 꺼내냐면 meta tag 속성을 살펴보면 됩니다.

<meta property="og:title" content="Apple 2020 맥북 에어 13">

 

 

 

 

[head -> meta 에서 property가 'og:title' 인것의 content라는 속성을 꺼내줘] 라고 한다면 html 패키지에서는 아래처럼 코드를 작성하면 됩니다.

 

정말 간단하게 원하는 tag 정보를 가져올 수 있습니다.

dom.Document document = parse.parse(response.body);

String? title = document.head
    ?.querySelector("meta[property='og:title']")
    ?.attributes['content'];
String? description = document.head
    ?.querySelector("meta[property='og:description']")
    ?.attributes['content'];
String? image = document.head
    ?.querySelector("meta[property='og:image']")
    ?.attributes['content'];
String? url = document.head
    ?.querySelector("meta[property='og:url']")
    ?.attributes['content'];

 

 

 

 

전체 코드 입니다.

 

return type은 원하는 model을 생성해서 응답해주면 딱이겠군요!

import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parse;

static void urlToMeta(String uri) async {
    final response = await http.get(Uri.parse(uri), headers: {
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
    }).timeout(const Duration(seconds: 2));
    dom.Document document = parse.parse(response.body);

    String? title = document.head
        ?.querySelector("meta[property='og:title']")
        ?.attributes['content'];
    String? description = document.head
        ?.querySelector("meta[property='og:description']")
        ?.attributes['content'];
    String? image = document.head
        ?.querySelector("meta[property='og:image']")
        ?.attributes['content'];
    String? url = document.head
        ?.querySelector("meta[property='og:url']")
        ?.attributes['content'];
 }

 

 

 

# 마무리

Flutter 뿐만 아니라 다른 언어에서도 방법만 안다면 문제없어 원하는 정보를 Crawling 할 수 있습니다.

 

728x90
반응형
728x90
반응형

 

플러터로 개발중에 sdk 를 3.3.0 으로 버전업을 한 뒤로 firebase_messging을 사용하는 Android에서 BackgroundHandler함수 호출을 못하는 문제점이 생겼어요.

 

 

문제발생

당황스러운건 Debug 모드에서는 정상적으로 호출이 되다가 Release 모드에서만 갑자기 동작을 안해서 오류가 있는지도 몰랐다는 것이었죠.

 

release 모드로 빌드를 한다음 해당 오류가 발생하는것을 알게되었습니다.

flutter run --release
E/flutter (12708): [ERROR:flutter/lib/ui/dart_runtime_hooks.cc(38)] Dart Error: Unhandled exception:
E/flutter (12708): NoSuchMethodError: No top-level getter '_firebaseMessagingBackgroundHandler' declared.
E/flutter (12708): Receiver: top-level
E/flutter (12708): Tried calling: _firebaseMessagingBackgroundHandler
E/flutter (12708): #0      NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:225)
E/flutter (12708): #1      FfiTrampoline___getCallbackFromHandle$Method$FfiNative$Ptr (dart:ffi)
E/flutter (12708): #2      _getCallbackFromHandle (dart:ui/natives.dart:141)
E/flutter (12708): #3      PluginUtilities.getCallbackFromHandle.<anonymous closure> (dart:ui/plugins.dart:81)
E/flutter (12708): #4      _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:524)
E/flutter (12708): #5      PluginUtilities.getCallbackFromHandle (dart:ui/plugins.dart:80)
E/flutter (12708): #6      _firebaseMessagingCallbackDispatcher.<anonymous closure> (package:firebase_messaging_platform_interface/src/method_channel/method_channel_messaging.dart:40)
E/flutter (12708): #7      MethodChannel._handleAsMethodCall (package:flutter/src/services/platform_channel.dart:555)
E/flutter (12708): #8      MethodChannel.setMethodCallHandler.<anonymous closure> (package:flutter/src/services/platform_channel.dart:548)
E/flutter (12708): #9      _DefaultBinaryMessenger.setMessageHandler.<anonymous closure> (package:flutter/src/services/binding.dart:393)
E/flutter (12708): #10     _invoke2 (dart:ui/hooks.dart:183)
E/flutter (12708): #11     _ChannelCallbackRecord.invoke (dart:ui/channel_buffers.dart:40)
E/flutter (12708): #12     _Channel.push (dart:ui/channel_buffers.dart:130)
E/flutter (12708): #13     ChannelBuffers.push (dart:ui/channel_buffers.dart:326)
E/flutter (12708): #14     PlatformDispatcher._dispatchPlatformMessage (dart:ui/platform_dispatcher.dart:664)
E/flutter (12708): #15     _dispatchPlatformMessage (dart:ui/hooks.dart:86)

 

 

 

이슈확인

NoSuchMethodError: No top-level getter '_firebaseMessagingBackgroundHandler' declared. 오류로 고통받는 개발자가 많이 생길것이라고 봅니다.

 

문제점 해결은 github 링크를 참고했습니다.

 

https://github.com/firebase/flutterfire/issues/9446#issuecomment-1240554285

 

🐛 [firebase_messaging] `onBackgroundMessage` is never called when using Flutter 3.3.0 in release mode on Android · Issue #94

Bug report When an app using firebase_messaging is built using Flutter 3.3.0, onBackgroundMessage is not being called at all on Android. When using Flutter 3.0.5, the app receives notifications in ...

github.com

 

 

 

해결

backgroundHandler에 @pragma 애노테이션을 작성하고 다시 Release 모드로 시작하면 문제가 사라진것을 알 수 있습니다.

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  ...
}

 

https://api.dart.dev/stable/2.1.0/dart-core/pragma-class.html

 

pragma class - dart:core library - Dart API

pragma class A hint to tools. Tools that work with Dart programs may accept hints to guide their behavior as pragma annotations on declarations. Each tool decides which hints it accepts, what they mean, and whether and how they apply to sub-parts of the an

api.dart.dev

 

 

 

 

firease_messaging Release모드에서 백그라운드 알림 수신을 하지 않는다는것은 정말 치명적이네요.

 

firebase_messaging을 사용하시는 분들에게 문제점 해결에 도움이 되었으면 합니다.

 

728x90
반응형

+ Recent posts