Skip to content

Commit

Permalink
Merge branch 'master' into feat/spm
Browse files Browse the repository at this point in the history
# Conflicts:
#	ios/Plugin.xcodeproj/project.pbxproj
#	ios/Plugin/Plugin.m
  • Loading branch information
rdlabo committed Nov 27, 2024
2 parents 852f415 + fbb5b9b commit 664fda2
Show file tree
Hide file tree
Showing 19 changed files with 740 additions and 67 deletions.
323 changes: 259 additions & 64 deletions README.md

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions android/src/main/java/com/getcapacitor/community/admob/AdMob.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.getcapacitor.community.admob.interstitial.AdInterstitialExecutor;
import com.getcapacitor.community.admob.interstitial.InterstitialAdCallbackAndListeners;
import com.getcapacitor.community.admob.rewarded.AdRewardExecutor;
import com.getcapacitor.community.admob.rewardedinterstitial.AdRewardInterstitialExecutor;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.RequestConfiguration;
import com.google.android.gms.ads.initialization.InitializationStatus;
Expand All @@ -39,6 +40,12 @@ public class AdMob extends Plugin {
this::notifyListeners,
getLogTag()
);
private final AdRewardInterstitialExecutor adRewardInterstitialExecutor = new AdRewardInterstitialExecutor(
this::getContext,
this::getActivity,
this::notifyListeners,
getLogTag()
);
private final AdInterstitialExecutor adInterstitialExecutor = new AdInterstitialExecutor(
this::getContext,
this::getActivity,
Expand Down Expand Up @@ -169,6 +176,16 @@ public void showRewardVideoAd(final PluginCall call) {
adRewardExecutor.showRewardVideoAd(call, this::notifyListeners);
}

@PluginMethod
public void prepareRewardInterstitialAd(final PluginCall call) {
adRewardInterstitialExecutor.prepareRewardInterstitialAd(call, this::notifyListeners);
}

@PluginMethod
public void showRewardInterstitialAd(final PluginCall call) {
adRewardInterstitialExecutor.showRewardInterstitialAd(call, this::notifyListeners);
}

/**
* @see <a href="https://developers.google.com/admob/android/test-ads#enable_test_devices">Test Devices</a>
* @see <a href="https://developers.google.com/admob/android/targeting">Target Settings</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public abstract class AdOptions {
public static final String BANNER_TESTER_ID = "ca-app-pub-3940256099942544/6300978111";
public static final String INTERSTITIAL_TESTER_ID = "ca-app-pub-3940256099942544/1033173712";
public static final String REWARD_VIDEO_TESTER_ID = "ca-app-pub-3940256099942544/5224354917";
public static final String REWARD_INTERSTITIAL_TESTER_ID = "ca-app-pub-3940256099942544/5354046379";

/**
* The position of the ad, it can be TOP_CENTER,
Expand Down Expand Up @@ -138,6 +139,15 @@ public String getTestingId() {
};
}

public AdOptions createRewardInterstitialOptions(PluginCall call) {
return new AdOptions(call) {
@Override
public String getTestingId() {
return AdOptions.REWARD_INTERSTITIAL_TESTER_ID;
}
};
}

public AdOptions createGenericOptions(PluginCall call, final String testingID) {
return new AdOptions(call) {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.getcapacitor.community.admob.rewardedinterstitial;

import android.app.Activity;
import android.content.Context;
import androidx.core.util.Supplier;
import com.getcapacitor.JSObject;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.community.admob.helpers.AdViewIdHelper;
import com.getcapacitor.community.admob.helpers.RequestHelper;
import com.getcapacitor.community.admob.models.AdMobPluginError;
import com.getcapacitor.community.admob.models.AdOptions;
import com.getcapacitor.community.admob.models.Executor;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd;
import com.google.android.gms.common.util.BiConsumer;

public class AdRewardInterstitialExecutor extends Executor {

public static RewardedInterstitialAd mRewardedInterstitialAd;

public AdRewardInterstitialExecutor(
Supplier<Context> contextSupplier,
Supplier<Activity> activitySupplier,
BiConsumer<String, JSObject> notifyListenersFunction,
String pluginLogTag
) {
super(contextSupplier, activitySupplier, notifyListenersFunction, pluginLogTag, "AdRewardExecutor");
}

@PluginMethod
public void prepareRewardInterstitialAd(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
final AdOptions adOptions = AdOptions.getFactory().createRewardInterstitialOptions(call);

activitySupplier
.get()
.runOnUiThread(
() -> {
try {
final AdRequest adRequest = RequestHelper.createRequest(adOptions);
final String id = AdViewIdHelper.getFinalAdId(adOptions, adRequest, logTag, contextSupplier.get());
RewardedInterstitialAd.load(
contextSupplier.get(),
id,
adRequest,
RewardedInterstitialAdCallbackAndListeners.INSTANCE.getRewardedAdLoadCallback(
call,
notifyListenersFunction,
adOptions
)
);
} catch (Exception ex) {
call.reject(ex.getLocalizedMessage(), ex);
}
}
);
}

@PluginMethod
public void showRewardInterstitialAd(final PluginCall call, BiConsumer<String, JSObject> notifyListenersFunction) {
if (mRewardedInterstitialAd == null) {
String errorMessage = "No Reward Video Ad can be show. It was not prepared or maybe it failed to be prepared.";
call.reject(errorMessage);
AdMobPluginError errorObject = new AdMobPluginError(-1, errorMessage);
notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.FailedToLoad, errorObject);
return;
}

try {
activitySupplier
.get()
.runOnUiThread(
() -> {
mRewardedInterstitialAd.show(
activitySupplier.get(),
RewardedInterstitialAdCallbackAndListeners.INSTANCE.getOnUserEarnedRewardListener(call, notifyListenersFunction)
);
}
);
} catch (Exception ex) {
call.reject(ex.getLocalizedMessage(), ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.getcapacitor.community.admob.rewardedinterstitial

import com.getcapacitor.community.admob.models.LoadPluginEventNames

object RewardInterstitialAdPluginEvents: LoadPluginEventNames {
const val Loaded = "onRewardedInterstitialAdLoaded"
const val FailedToLoad = "onRewardedInterstitialAdFailedToLoad"
const val Rewarded = "onRewardedInterstitialAdReward"
override val Showed = "onRewardedInterstitialAdShowed"
override val FailedToShow = "onRewardedInterstitialAdFailedToShow"
override val Dismissed = "onRewardedInterstitialAdDismissed"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.getcapacitor.community.admob.rewardedinterstitial

import com.getcapacitor.JSObject
import com.getcapacitor.PluginCall
import com.getcapacitor.community.admob.helpers.FullscreenPluginCallback
import com.getcapacitor.community.admob.models.AdMobPluginError
import com.getcapacitor.community.admob.models.AdOptions
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.OnUserEarnedRewardListener
import com.google.android.gms.ads.rewarded.RewardItem
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback
import com.google.android.gms.common.util.BiConsumer

object RewardedInterstitialAdCallbackAndListeners {

fun getOnUserEarnedRewardListener(call: PluginCall, notifyListenersFunction: BiConsumer<String, JSObject>): OnUserEarnedRewardListener {
return OnUserEarnedRewardListener { item: RewardItem ->
val response = JSObject()
response.put("type", item.type)
.put("amount", item.amount)
notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.Rewarded, response)
call.resolve(response)
}
}

fun getRewardedAdLoadCallback(call: PluginCall, notifyListenersFunction: BiConsumer<String, JSObject>, adOptions: AdOptions): RewardedInterstitialAdLoadCallback {
return object : RewardedInterstitialAdLoadCallback() {
override fun onAdLoaded(ad: RewardedInterstitialAd) {
AdRewardInterstitialExecutor.mRewardedInterstitialAd = ad
AdRewardInterstitialExecutor.mRewardedInterstitialAd.fullScreenContentCallback = FullscreenPluginCallback(
RewardInterstitialAdPluginEvents, notifyListenersFunction)

val adInfo = JSObject()
adInfo.put("adUnitId", ad.adUnitId)
call.resolve(adInfo)

notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.Loaded, adInfo)
}

override fun onAdFailedToLoad(adError: LoadAdError) {
val adMobError = AdMobPluginError(adError)

notifyListenersFunction.accept(RewardInterstitialAdPluginEvents.FailedToLoad, adMobError)
call.reject(adError.message)
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.getcapacitor.community.admob.rewardedinterstitial.models

import com.getcapacitor.PluginCall

class SsvInfo(
val customData: String? = null,
val userId: String? = null) {

constructor(pluginCall: PluginCall?) : this(
pluginCall?.getObject("ssv")?.getString("customData"),
pluginCall?.getObject("ssv")?.getString("userId")
)

constructor() : this(null, null)

val hasInfo
get(): Boolean {
return customData != null || userId != null
}
}
12 changes: 10 additions & 2 deletions demo/angular/src/app/shared/ad.options.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {BannerAdOptions, BannerAdPosition, BannerAdSize} from '../../../../../dist/esm/banner';
import {AdOptions} from '../../../../../dist/esm/shared';
import {
BannerAdOptions,
BannerAdPosition,
BannerAdSize,
} from '../../../../../dist/esm/banner';
import { AdOptions } from '../../../../../dist/esm/shared';

export const bannerTopOptions: BannerAdOptions = {
adId: 'ca-app-pub-3940256099942544/2934735716',
Expand All @@ -19,6 +23,10 @@ export const rewardOptions: AdOptions = {
adId: 'ca-app-pub-3940256099942544/5224354917',
};

export const rewardInterstitialOptions: AdOptions = {
adId: 'ca-app-pub-3940256099942544/5354046379',
};

export const interstitialOptions: AdOptions = {
adId: 'ca-app-pub-3940256099942544/1033173712',
};
24 changes: 23 additions & 1 deletion ios/Sources/AdMobPlugin/AdMobPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
private let bannerExecutor = BannerExecutor()
private let adInterstitialExecutor = AdInterstitialExecutor()
private let adRewardExecutor = AdRewardExecutor()
private let adRewardInterstitialExecutor = AdRewardInterstitialExecutor()
private let consentExecutor = ConsentExecutor()

/**
Expand All @@ -43,6 +44,8 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
self.bannerExecutor.plugin = self
self.adInterstitialExecutor.plugin = self
self.adRewardExecutor.plugin = self
self.adRewardInterstitialExecutor.plugin = self
self.adInterstitialExecutor.plugin = self
self.consentExecutor.plugin = self
self.setRequestConfiguration(call)

Expand Down Expand Up @@ -143,7 +146,7 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {

/**
* AdMob: Rewarded Ads
* https://developers.google.com/ad-manager/mobile-ads-sdk/ios/rewarded-ads?hl=ja
* https://developers.google.com/ad-manager/mobile-ads-sdk/ios/rewarded-ads
*/
@objc func prepareRewardVideoAd(_ call: CAPPluginCall) {
let adUnitID = getAdId(call, "ca-app-pub-3940256099942544/1712485313")
Expand All @@ -159,6 +162,25 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
self.adRewardExecutor.showRewardVideoAd(call)
}
}

/**
* AdMob: Rewarded Interstitial Ads
* https://developers.google.com/ad-manager/mobile-ads-sdk/ios/rewarded-interstitial
*/
@objc func prepareRewardInterstitialAd(_ call: CAPPluginCall) {
let adUnitID = getAdId(call, "ca-app-pub-3940256099942544/6978759866")
let request = self.GADRequestWithOption(call.getBool("npa") ?? false)

DispatchQueue.main.async {
self.adRewardInterstitialExecutor.prepareRewardInterstitialAd(call, request, adUnitID)
}
}

@objc func showRewardInterstitialAd(_ call: CAPPluginCall) {
DispatchQueue.main.async {
self.adRewardInterstitialExecutor.showRewardInterstitialAd(call)
}
}

@objc func trackingAuthorizationStatus(_ call: CAPPluginCall) {
DispatchQueue.main.async {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import Foundation
import Capacitor
import GoogleMobileAds

class AdRewardInterstitialExecutor: NSObject, GADFullScreenContentDelegate {
public weak var plugin: AdMob?
var rewardedInterstitialAd: GADRewardedInterstitialAd!

func prepareRewardInterstitialAd(_ call: CAPPluginCall, _ request: GADRequest, _ adUnitID: String) {
GADRewardedInterstitialAd.load(
withAdUnitID: adUnitID,
request: request,
completionHandler: { (ad, error) in
if let error = error {
NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)")
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.FailedToLoad.rawValue, data: [
"code": 0,
"message": error.localizedDescription
])
call.reject("Loading failed")
return
}

self.rewardedInterstitialAd = ad

if let providedOptions = call.getObject("ssv") {
let ssvOptions = GADServerSideVerificationOptions()

if let customData = providedOptions["customData"] as? String {
NSLog("Sending Custom Data: \(customData) to SSV callback")
ssvOptions.customRewardString = customData
}

if let userId = providedOptions["userId"] as? String {
NSLog("Sending UserId: \(userId) to SSV callback")
ssvOptions.userIdentifier = userId
}

self.rewardedInterstitialAd?.serverSideVerificationOptions = ssvOptions
}

self.rewardedInterstitialAd?.fullScreenContentDelegate = self
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Loaded.rawValue, data: [
"adUnitId": adUnitID
])
call.resolve([
"adUnitId": adUnitID
])
}
)
}

func showRewardInterstitialAd(_ call: CAPPluginCall) {
if let rootViewController = plugin?.getRootVC() {
if let ad = self.rewardedInterstitialAd {
ad.present(fromRootViewController: rootViewController,
userDidEarnRewardHandler: {
let reward = ad.adReward
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Rewarded.rawValue, data: ["type": reward.type, "amount": reward.amount])
call.resolve(["type": reward.type, "amount": reward.amount])
}
)
} else {
call.reject("Reward Video is Not Ready Yet")
}
}
}

public func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.FailedToShow.rawValue, data: [
"code": 0,
"message": error.localizedDescription
])
}

public func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
NSLog("RewardFullScreenDelegate Ad did present full screen content.")
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Showed.rawValue, data: [:])
}

public func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.")
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Dismissed.rawValue, data: [:])
}
}
Loading

0 comments on commit 664fda2

Please sign in to comment.