Compose Multiplatform で Admobのバナー広告を表示する
概要
Compose Multiplatform で、Android/iOSの環境で Admob のバナー広告を表示する方法を解説します。
バナー広告を表示する手順は以下の通りです。
- commonMain 以下で、 AdFactoryインターフェイスを作成する。AdFactoryはバナー広告を表示する AdBanner() メソッドを持つ。
- androidMain と iosMain 以下で、AdFactory を継承した AdFactoryImpl を実装する。そして、Koinを使って commonMainから呼び出せるようにする。
- commonMain 以下で、Compose Multiplatformで作成した画面内で、AdFactory.AdBanner() を呼び出す。
使用するライブラリ
- Mobile Ads SDK (Android) (opens in a new tab)
- Mobile Ads SDK (iOS) (opens in a new tab)
- Compose Multiplatform (opens in a new tab)
- Koin (opens in a new tab)
- voyager (opens in a new tab)
実装
commonMain
commonMain/../ad/AdFactory.kt
import androidx.compose.runtime.Composable
interface AdFactory {
@Composable
fun AdBanner()
}
commonMain/../ui/screens/MainScreen.kt
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class MainScreen : Screen, KoinComponent {
@Composable
override fun Content() {
val adFactory: AdFactory by inject()
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Spacer(Modifier.weight(1f))
// バナー広告を表示
adFactory.AdBanner()
}
}
}
androidMain
androidMain/../ad/AdFactoryImpl.kt
import android.content.Context
import android.content.res.Resources
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView
class AdFactoryImpl : AdFactory {
@Composable
override fun AdBanner() {
if (LocalInspectionMode.current) {
// プレビュー時は表示しない
return
}
val displayMetrics = Resources.getSystem().displayMetrics
val width = ((displayMetrics.widthPixels) / displayMetrics.density).toInt()
val adSize = getAdBannerSize(LocalContext.current, width)
val heightDp = with(LocalDensity.current) {
adSize.getHeightInPixels(LocalContext.current).toDp()
}
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(heightDp),
factory = { context ->
val adView = AdView(context)
adView.setAdSize(adSize)
adView.adUnitId = Admob.getAdBannerUnitId()
adView.loadAd(AdRequest.Builder().build())
adView
},
)
}
private fun getAdBannerSize(context: Context, width: Int): AdSize {
return if (Admob.IS_BANNER_HIDDEN) {
AdSize(width, 0)
} else {
AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(context, width)
}
}
}
androidMain/../MainApplication.kt
class MainApplication : Application(), Application.ActivityLifecycleCallbacks, LifecycleObserver,
KoinComponent {
override fun onCreate() {
super.onCreate()
MobileAds.initialize(this) { }
startKoin {
androidContext(this@MainApplication)
modules(appModule)
}
}
androidMain/../AppModule.kt
import org.koin.dsl.module
val appModule = module {
single<AdFactory> { AdFactoryImpl() }
}
iosMain
iosMain/../ad/AdFactoryImpl.kt
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.interop.UIKitView
import androidx.compose.ui.unit.dp
import kotlinx.cinterop.ExperimentalForeignApi
class AdFactoryImpl(private val adBannerViewFactory: AdBannerViewFactory) : AdFactory {
@OptIn(ExperimentalForeignApi::class)
@Composable
override fun AdBanner() {
UIKitView(
factory = {
adBannerViewFactory.createAdBannerView()
},
modifier = Modifier.fillMaxWidth().height(adBannerViewFactory.getHeight().dp)
)
}
}
iosMain/../ad/AdBannerViewFactory.kt
import platform.UIKit.UIView
interface AdBannerViewFactory {
fun createAdBannerView(): UIView
fun getHeight(): Int
}
iosMain/../KoinHelper.kt
import org.koin.core.context.startKoin
import org.koin.dsl.module
fun initKoin(
adBannerViewFactory: AdBannerViewFactory
) {
startKoin {
modules(module {
single<AdFactory> { AdFactoryImpl(adBannerViewFactory) }
})
}
}
iosApp
iosApp/Ad/AdBannerViewFactoryImpl.swift
import Foundation
import GoogleMobileAds
import shared
class AdBannerViewFactoryImpl: AdBannerViewFactory {
func createAdBannerView() -> UIView {
let bannerView = GADBannerView(adSize: GADAdSizeBanner)
bannerView.adUnitID = Admob.getBannerAdUnitId()
bannerView.rootViewController = UIWindow.getWindow()?.rootViewController
bannerView.adSize = getAdSize(width: UIScreen.screenWidth)
bannerView.load(GADRequest())
return bannerView
}
func getHeight() -> Int32 {
return Int32(getAdSize(width: UIScreen.screenWidth).size.height)
}
private func getAdSize(width: CGFloat) -> GADAdSize {
if Admob.IsBannerHidden {
return GADAdSize()
} else {
return GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(width)
}
}
}
iosApp/Extension/UIWindow+.swift
import UIKit
extension UIWindow {
static func getWindow() -> UIWindow? {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
return windowScene?.windows.first
}
}
iosApp/Extension/UIScreen+.swift
import UIKit
extension UIScreen {
static let screenWidth = UIScreen.main.bounds.size.width
static let screenHeight = UIScreen.main.bounds.size.height
static let screenSize = UIScreen.main.bounds.size
}
iosApp/iOSApp.swift
import SwiftUI
import GoogleMobileAds
import shared
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
GADMobileAds.sharedInstance().start(completionHandler: nil)
return true
}
}
@main
struct iOSApp: App {
// register app delegate for Firebase setup
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
init() {
KoinHelperKt.doInitKoin(
adBannerViewFactory: AdBannerViewFactoryImpl()
)
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}