Flutter Android原生广告报错找不到id为homeScreen的NativeAdFactory
Flutter Android端原生广告加载报错:Can't find NativeAdFactory with id: homeScreen
报错信息
PlatformException(NativeAdError, Can't find NativeAdFactory with id: homeScreen, null, null)
环境信息
使用的google_mobile_ads插件版本:
google_mobile_ads: ^0.13.0
现有代码实现
HomeScreenNativeAd.kt 原生广告工厂实现
class HomeScreenNativeAd(val context: Context) : GoogleMobileAdsPlugin.NativeAdFactory { override fun createNativeAd( nativeAd: NativeAd, customOptions: MutableMap<String, Any>? ): NativeAdView { val homeScreenNativeView = LayoutInflater.from(context) .inflate(R.layout.home_screen_native_ad, null) as NativeAdView with(homeScreenNativeView) { val attributionViewSmall = findViewById<TextView>(R.id.tv_home_item_native_ad_attribution_small) val icon = findViewById<ImageView>(R.id.home_item_bg_image) val image = nativeAd.icon if (image != null) { attributionViewSmall.visibility = View.VISIBLE icon.setImageDrawable(image.drawable) } else { attributionViewSmall.visibility = View.INVISIBLE } this.iconView = iconView val adV = findViewById<TextView>(R.id.adviser) adV.text = nativeAd.advertiser this.advertiserView =adV val ctaButton = findViewById<TextView>(R.id.home_screen_cta_button) ctaButton.text = nativeAd.callToAction this.callToActionView = ctaButton val adDesc = findViewById<TextView>(R.id.home_item_ad_desc) adDesc.text = nativeAd.body this.bodyView = ctaButton val headlineView = findViewById<TextView>(R.id.home_item_ad_title) headlineView.text = nativeAd.headline this.headlineView = headlineView setNativeAd(nativeAd) } return homeScreenNativeView } }
home_screen_native_ad.xml 广告布局文件
<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"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="160dp"> <FrameLayout android:layout_width="match_parent" android:background="#00ffffff" android:layout_height="140dp"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="190dp" android:layout_marginTop="16dp" android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" android:gravity="start" android:orientation="horizontal"> <ImageView android:id="@+id/home_item_bg_image" android:layout_width="60dp" android:layout_height="60dp" android:scaleType="centerCrop" android:layout_marginLeft="16dp"/> <TextView android:id="@+id/home_item_ad_title" android:layout_width="220dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_toRightOf="@+id/home_item_bg_image" android:ellipsize="end" android:lines="1" android:maxLines="1" android:textColor="#FFFFFFFF" android:textSize="20sp" tools:text="Headline" /> <TextView android:id="@+id/adviser" android:layout_width="229dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="32dp" android:layout_toRightOf="@+id/home_item_bg_image" android:ellipsize="end" android:lines="1" android:maxLines="1" android:textColor="#FFFFFFFF" android:textSize="14sp" tools:text="Advertiser" /> <TextView android:id="@+id/tv_home_item_native_ad_attribution_small" android:layout_width="35dp" android:layout_height="20dp" android:layout_marginLeft="10dp" android:layout_toRightOf="@+id/home_item_ad_title" android:background="@color/softOrange" android:gravity="center" android:lines="1" android:maxLines="1" android:text="Ad" android:textColor="#FFFF" android:textSize="12sp" /> </RelativeLayout> <TextView android:id="@+id/home_item_ad_desc" android:layout_width="270dp" android:layout_height="40dp" android:layout_marginTop="85dp" android:ellipsize="end" android:lines="2" android:gravity="center_vertical" android:maxLines="2" android:textColor="#FFFFFFFF" android:textSize="14sp" android:layout_marginLeft="16dp" tools:text="Headline" /> <TextView android:id="@+id/home_screen_cta_button" android:layout_width="wrap_content" android:layout_marginLeft="10dp" android:layout_height="30dp" android:layout_toRightOf="@+id/home_item_ad_desc" android:layout_marginTop="100dp" android:text="INSTALL" android:gravity="center" android:ellipsize="end" android:lines="1" android:textColor="#FFF" android:maxLines="1" android:textSize="18sp"/> </RelativeLayout> </FrameLayout> </com.google.android.gms.ads.nativead.NativeAdView>
MainActivity.kt 注册逻辑
class MainActivity : FlutterActivity() { private val CHANNEL = "verified.cv/channel" // 与main.dart中设置的渠道名一致 override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> if (call.method == "createNotificationChannel") { val argData = call.arguments as java.util.HashMap<String, String> val completed = createNotificationChannel(argData) if (completed == true) { result.success(completed) } else { result.error("Error Code", "Error Message", null) } } else { result.notImplemented() } } GoogleMobileAdsPlugin.registerNativeAdFactory( flutterEngine, "listTile", ListTileNativeAdFactory(context)) GoogleMobileAdsPlugin.registerNativeAdFactory( flutterEngine, "skillCard", SkillCardNativeFactory(context)) GoogleMobileAdsPlugin.registerNativeAdFactory( flutterEngine, "homeScreen", HomeScreenNativeAd(context)) GoogleMobileAdsPlugin.registerNativeAdFactory( flutterEngine, "feedItem", FeedItemNativeFactory(context)) } override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) { super.cleanUpFlutterEngine(flutterEngine) GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile") GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "skillCard") GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "homeScreen") GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "feedItem") } private fun createNotificationChannel(mapData: HashMap<String, String>): Boolean { val completed: Boolean if (VERSION.SDK_INT >= VERSION_CODES.O) { val id = mapData["id"] val name = mapData["name"] val descriptionText = mapData["description"] val importance = NotificationManager.IMPORTANCE_HIGH val mChannel = NotificationChannel(id, name, importance) mChannel.description = descriptionText val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(mChannel) completed = true } else { completed = false } return completed } }
错误日志
I/flutter ( 1409): ----------------FIREBASE CRASHLYTICS---------------- I/flutter ( 1409): PlatformException(NativeAdError, Can't find NativeAdFactory with id: homeScreen, null, null) I/flutter ( 1409): #0 StandardMethodCodec.decodeEnvelope package:flutter/…/services/message_codecs.dart:607 I/flutter ( 1409): #1 MethodChannel._invokeMethod package:flutter/…/services/platform_channel.dart:177 I/flutter ( 1409): <asynchronous suspension> I/flutter ( 1409): #2 NativeAd.load package:google_mobile_ads/src/ad_containers.dart:1033 I/flutter ( 1409): <asynchronous suspension> I/flutter ( 1409): ---------------------------------------------------- D/ACodec ( 1409): dataspace changed to 0x10c40000 (R:2(Limited), P:4(BT601_6_525), M:3(BT601_6), T:3(SMPTE170M))
排查解决步骤
- 检查Dart端广告初始化的factoryId一致性
确认Dart侧创建NativeAd实例时传入的factoryId参数完全等于"homeScreen",注意大小写、前后空格都不能有差异,这是最高发的低级错误。 - 检查注册时机问题
你当前在configureFlutterEngine中注册的位置是正确的,但如果应用使用了多FlutterEngine、或者广告在FlutterEngine完全初始化前就触发加载,会出现注册未完成就查找工厂的情况。可以在注册homeScreen工厂的位置加日志打印,确认广告加载前注册逻辑已经执行。 - 修复代码里的变量赋值错误
你的HomeScreenNativeAd.kt里有两处明显的赋值错误,会导致广告工厂初始化崩溃,插件捕获异常后会直接返回找不到工厂的错误:- 第一处:你定义了
val icon = findViewById<ImageView>(R.id.home_item_bg_image),但后面赋值时写的是this.iconView = iconView,这里iconView未定义,应该改成this.iconView = icon - 第二处:你给广告描述赋值时写的是
this.bodyView = ctaButton,错误地把按钮控件赋值给了正文视图,应该改成this.bodyView = adDesc
- 第一处:你定义了
- 检查混淆规则
如果是release包出现该问题,需要在proguard规则里添加以下配置,防止广告工厂类被混淆:-keep class com.google.android.gms.ads.** { *; } -keep class * extends com.google.android.gms.ads.GoogleMobileAdsPlugin.NativeAdFactory { *; } - 清理缓存重新构建
执行flutter clean后重新运行应用,避免旧的构建缓存导致代码修改不生效。
额外提示:你当前使用的
google_mobile_ads 0.13.0是非常旧的版本,修复完上述问题后建议升级到官方稳定版,旧版本本身存在不少原生广告注册的已知bug。
内容的提问来源于stack exchange,提问作者Mehmet Kamay
相关产品推荐
相关产品推荐

