I am creating Flutter plugin that displays banner and interstitial ads in Flutter UI using Kotlin and Swift. When trying to show interstitial ad using Kotlin, I need to use Activity for that, which I am trying to get using onAttachedToActivity
, but my activity variable is always null.
I checked other questions related to this, but they are either using configureFlutterEngine
or have only one class.
I am using init
method instead of FlutterEngine
to add a layout in Flutter UI using Kotlin, which is later used to display banner (and banner works without any problems, so I removed that code part). I am adding all three Kotlin classes used for displaying ads.
Plugin class:
class SecondPluginAttemptPlugin: FlutterPlugin {
private var Tag: String = "MyTag"
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
Log.d(Tag, "SecondPluginAttemptPlugin attached to Flutter engine")
try {
binding.platformViewRegistry.registerViewFactory(
"plugins.example/second_attempt", MyViewFactory(binding.binaryMessenger)
)
Log.d(Tag, "MyViewFactory registered")
} catch (e: Exception) {
Log.e(Tag, "Error during registration: ${e.message}")
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
Log.d(Tag, "SecondPluginAttemptPlugin detached from Flutter engine")
}
}
Factory class:
class MyViewFactory (private val messenger: BinaryMessenger): PlatformViewFactory(StandardMessageCodec.INSTANCE){
override fun create(context: Context, id: Int, o: Any?) : PlatformView {
return MyView(context, messenger, id)
}
}
And my view class
class MyView internal constructor(context: Context, messenger: BinaryMessenger, id: Int) :
PlatformView, MethodCallHandler, ActivityAware {
private var applicationContext: Context = context
private var messageLayout: ViewGroup?
private val channel = MethodChannel(messenger, "plugins.example/second_attempt_$id")
private var mAdManagerInterstitialAd: AdManagerInterstitialAd? = null
private lateinit var myActivity: Activity
private val Tag = "MyTag"
init {
try {
Log.d(Tag, "init")
channel.setMethodCallHandler(this)
} catch (e: Exception) {
Log.e(Tag, "Error setting method call handler: $e")
}
messageLayout = FrameLayout(applicationContext)
messageLayout?.setBackgroundColor(Color.BLUE)
val params = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
params.gravity = Gravity.BOTTOM
}
override fun getView(): View? {
Log.d(Tag, "View")
return messageLayout
}
override fun dispose() {
Log.d(Tag, "Dispose")
messageLayout = null
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
Log.d(Tag, "onMethodCall " )
when (call.method) {
"setParams" -> settingParameters(call)
else -> result.notImplemented()
}
}
private fun settingParameters(call: MethodCall) {
val arguments = call.arguments as? Map<*, *>
val accountId = arguments?.get("prebidAccountId") as? String ?: ""
val adUnitId = arguments?.get("adUnitId") as? String ?: ""
val configId = arguments?.get("configId") as? String ?: ""
val width = arguments?.get("width") as? Int ?: 0
val height = arguments?.get("height") as? Int ?: 0
messageLayout?.removeAllViews()
val textView = TextView(applicationContext)
textView.setTextColor(Color.RED)
textView.gravity = Gravity.CENTER
//Skipped some code used to check if variables are not empty and if they are - a message is displayed inside messageLayout
createInterstitial(adUnitId)
}
private fun createInterstitial(AD_UNIT_ID: String) {
val adRequest = AdManagerAdRequest.Builder().build()
AdManagerInterstitialAd.load(applicationContext, AD_UNIT_ID, adRequest,
object : AdManagerInterstitialAdLoadCallback() {
override fun onAdLoaded(interstitialAd: AdManagerInterstitialAd) {
mAdManagerInterstitialAd = interstitialAd
Log.i(Tag, "onAdLoaded")
showInterstitial()
}
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
Log.d(Tag, loadAdError.toString())
mAdManagerInterstitialAd = null
}
})
}
private fun showInterstitial() {
if (mAdManagerInterstitialAd != null) {
mAdManagerInterstitialAd?.show(myActivity)
} else {
Log.d("TAG", "The interstitial ad wasn't ready yet.")
}
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
myActivity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
TODO("Not yet implemented")
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
TODO("Not yet implemented")
}
override fun onDetachedFromActivity() {
TODO("Not yet implemented")
}
}
Edit: so it seems my problem was adding ActivityAware
inside MyView
class instead of SecondPluginAttemptPlugin
. As for passing activity value to MyView
class, I used lateinit
and CompletableFuture<Activity>()
.
Use ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityAware
class SecondPluginAttemptPlugin : FlutterPlugin, ActivityAware {
private var activity: Activity? = null
//* * *
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onReattachedToActivityForConfigChanges(binding:ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {}
override fun onDetachedFromActivity() {}
}