googleads / googleads-mobile-flutter

A Flutter plugin for the Google Mobile Ads SDK
Apache License 2.0
344 stars 285 forks source link

App crashes when trying to load native ads #706

Closed ash-hashtag closed 1 year ago

ash-hashtag commented 1 year ago

I don't understand when or why it broke, I implemented native ads in my app 2 months ago and they were perfect, and I was like I'm done with ads, and never messed with them, the app is still in development, and now very soon will be published, I've tried to see is everything working fine, and the ads are now broke, tried with banner ads, seems fine, but we want only native ads, could anyone provide me with boilerplate/example of a working native ad implementation, with this package. We want to go public as soon as possible.. Thanks

Plugin Version

google_mobile_ads: ^2.0.0

Steps to Reproduce

  1. create a normal flutter app including google_mobile_ads package
  2. use the given files, for making up native ad

native_ad_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <androidx.cardview.widget.CardView
                android:id="@+id/view2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:elevation="0dp"
                android:innerRadius="0dp"
                android:shape="ring"
                android:thicknessRatio="1.9"
                app:cardCornerRadius="100dp">

                <ImageView
                    android:id="@+id/icon"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    tools:ignore="ImageContrastCheck,ImageContrastCheck,ImageContrastCheck,ImageContrastCheck"
                    tools:src="@tools:sample/avatars" />

            </androidx.cardview.widget.CardView>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:paddingHorizontal="10dp"
                android:paddingTop="10dp"
                >

                <TextView
                    android:id="@+id/title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Title"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/ad_attribution"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="advertisement" />
            </LinearLayout>

        </LinearLayout>

        <TextView
            android:id="@+id/body"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="Body" />

        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            tools:src="@tools:sample/avatars" />

        <com.google.android.gms.ads.nativead.MediaView
            android:id="@+id/media"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>
    </LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>

NativeAdFactory.kt


import android.content.Context
import android.opengl.Visibility
import android.provider.MediaStore
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import android.widget.VideoView
import com.google.android.gms.ads.nativead.MediaView
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdView
import io.flutter.Log
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin

class NativeAdFactory (val context: Context) : GoogleMobileAdsPlugin.NativeAdFactory {

    override fun createNativeAd(
        nativeAd: NativeAd,
        customOptions: MutableMap<String, Any>?
    ): NativeAdView {
        val nativeAdView = LayoutInflater.from(context)
            .inflate(R.layout.native_ad_layout, null) as NativeAdView

        with(nativeAdView) {
            val iconView = findViewById<ImageView>(R.id.icon)

            val icon = nativeAd.icon
            if (icon != null) {
                iconView.visibility = View.VISIBLE
                iconView.setImageDrawable(icon.drawable)
            } else {
                iconView.visibility = View.INVISIBLE
            }
            this.iconView = iconView

            val headlineView = findViewById<TextView>(R.id.title)
            headlineView.text = nativeAd.headline
            this.headlineView = headlineView

            val bodyView = findViewById<TextView>(R.id.body)
            with(bodyView) {
                text = nativeAd.body
                visibility = if (nativeAd.body?.isNotEmpty() == true) View.VISIBLE else View.INVISIBLE
            }
            this.bodyView = bodyView

            val imageView = findViewById<ImageView>(R.id.image)
            val videoView = findViewById<MediaView>(R.id.media)
            val video = nativeAd.mediaContent
            if (video != null && video.hasVideoContent()){
                videoView.visibility = View.VISIBLE
                videoView.setMediaContent(video)
            } else {
                videoView.visibility = View.INVISIBLE
            }
            this.mediaView = videoView
            val images = nativeAd.images
            if (images.isNullOrEmpty())
            {
                imageView.visibility = View.INVISIBLE
            } else {
                imageView.visibility = View.VISIBLE
                val id = (0..images.size).random()
                imageView.setImageDrawable(images.get(id).drawable)
                videoView.visibility = View.INVISIBLE
            }
            this.imageView = imageView

            setNativeAd(nativeAd)
        }

        return nativeAdView
    }
}

MainActivity.kt


import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        GoogleMobileAdsPlugin.registerNativeAdFactory(
            flutterEngine, "nativead", NativeAdFactory(context))
    }

    override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine)
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "nativead")
    }
}

native_ad.dart

class NativeAdWidget extends StatefulWidget {
  const NativeAdWidget({Key? key}) : super(key: key);

  @override
  State<NativeAdWidget> createState() => _NativeAdWidgetState();
}

class _NativeAdWidgetState extends State<NativeAdWidget> {
  NativeAd? ad;
  bool isAdloaded = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("loading ad");
    ad = NativeAd(
        adUnitId: Ads.ad_unit_id,
        factoryId: 'nativead',
        listener: NativeAdListener(
            onAdLoaded: (ad) =>
                setState(() => print('Ad loaded ${isAdloaded = true}')),
            onAdFailedToLoad: (_, err) =>
                setState(() => print('Ad ${ad = null} failed to load $err'))),
        request: const AdRequest())
      ..load();
  }

  @override
  void dispose() {
    super.dispose();
    ad?.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: SizedBox(
        height: ad != null && isAdloaded
            ? MediaQuery.of(context).size.height * 0.4
            : 0,
        child: ad != null && isAdloaded ? AdWidget(ad: ad!) : null,
      ),
    );
  }
}

Expected results: able to display native ads

Actual results: app crashing

Logs Logs from the moment, calling ad.load(), and then crashes. ``` E/AndroidRuntime(28245): at android.os.Binder.transact(Binder.java:1067) E/AndroidRuntime(28245): at aet.be(:com.google.android.gms.policy_ads_fdr_dynamite@223712200@223712200057.473771314.473771314:2) E/AndroidRuntime(28245): at com.google.android.gms.ads.internal.formats.client.al.e(:com.google.android.gms.policy_ads_fdr_dynamite@223712200@223712200057.473771314.473771314:0) E/AndroidRuntime(28245): at com.google.android.gms.ads.nonagon.ad.nativead.af.run(:com.google.android.gms.policy_ads_fdr_dynamite@223712200@223712200057.473771314.473771314:5) E/AndroidRuntime(28245): at android.os.Handler.handleCallback(Handler.java:938) E/AndroidRuntime(28245): at android.os.Handler.dispatchMessage(Handler.java:99) E/AndroidRuntime(28245): at asd.a(:com.google.android.gms.policy_ads_fdr_dynamite@223712200@223712200057.473771314.473771314:0) E/AndroidRuntime(28245): at com.google.android.gms.ads.internal.util.f.a(:com.google.android.gms.policy_ads_fdr_dynamite@223712200@223712200057.473771314.473771314:1) E/AndroidRuntime(28245): at asd.dispatchMessage(:com.google.android.gms.policy_ads_fdr_dynamite@223712200@223712200057.473771314.473771314:0) E/AndroidRuntime(28245): at android.os.Looper.loopOnce(Looper.java:210) E/AndroidRuntime(28245): at android.os.Looper.loop(Looper.java:299) E/AndroidRuntime(28245): at android.app.ActivityThread.main(ActivityThread.java:8298) E/AndroidRuntime(28245): at java.lang.reflect.Method.invoke(Native Method) E/AndroidRuntime(28245): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:576) E/AndroidRuntime(28245): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1073) Lost connection to device. ``` ``` ``` ``` [√] Flutter (Channel stable, 3.3.8, on Microsoft Windows [Version 10.0.22623.891], locale en-IN) • Flutter version 3.3.8 on channel stable at C:\src\flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 52b3dc25f6 (2 weeks ago), 2022-11-09 12:09:26 +0800 • Engine revision 857bd6b74c • Dart version 2.18.4 • DevTools version 2.15.0 [√] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1) • Android SDK at C:\Users\SPT\AppData\Local\Android\sdk • Platform android-33, build-tools 32.1.0-rc1 • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) • All Android licenses accepted. [X] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe) ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable. [√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.4.1) • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community • Visual Studio Community 2022 version 17.4.33110.190 • Windows 10 SDK version 10.0.22621.0 [√] Android Studio (version 2021.3) • Android Studio at C:\Program Files\Android\Android Studio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) [√] VS Code (version 1.73.1) • VS Code at C:\Users\SPT\AppData\Local\Programs\Microsoft VS Code • Flutter extension version 3.52.0 [√] Connected device (3 available) • M2101K7BI (mobile) • X84LCAF6QS85KZAE • android-arm64 • Android 12 (API 31) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.22623.891] • Edge (web) • edge • web-javascript • Microsoft Edge 107.0.1418.42 [√] HTTP Host Availability • All required HTTP hosts are available ! Doctor found issues in 1 category. ```
huycozy commented 1 year ago

Hi @ash-hashtag Please try running google_mobile_ads sample code and check if there is a crash.

If the crash still persists, please provide the output of flutter run -v along with the affected device info. Thanks!

ash-hashtag commented 1 year ago

thanks, I don't know what exactly was the problem, but It fixed when I re implemented with the given example