Skip to content
This repository has been archived by the owner on Apr 27, 2022. It is now read-only.

Commit

Permalink
refactor: improve AppOpenAd logic
Browse files Browse the repository at this point in the history
  • Loading branch information
wjaykim committed Aug 20, 2021
1 parent 586169d commit e65a458
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 85 deletions.
11 changes: 8 additions & 3 deletions android/build.gradle
Expand Up @@ -2,11 +2,11 @@ buildscript {
if (project == rootProject) {
repositories {
google()
jcenter()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:4.2.1'
}
}
}
Expand Down Expand Up @@ -55,5 +55,10 @@ repositories {
dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation 'com.google.android.gms:play-services-ads:+'
implementation 'com.google.android.gms:play-services-ads:[20.0, 21.0['

def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
}
87 changes: 77 additions & 10 deletions android/src/main/java/com/rnadmob/admob/RNAdMobAppOpenAdModule.java
Expand Up @@ -10,6 +10,10 @@

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
Expand All @@ -26,12 +30,17 @@

import java.util.Date;

public class RNAdMobAppOpenAdModule extends ReactContextBaseJavaModule {
public class RNAdMobAppOpenAdModule extends ReactContextBaseJavaModule implements LifecycleObserver {

public static final String REACT_CLASS = "RNAdMobAppOpen";

private Promise presentPromise = null;
private AppOpenAd appOpenAd = null;
private volatile String unitId = null;
private ReadableMap requestOptions = null;
private boolean showOnAppForeground = true;
private boolean showOnColdStart = false;
private boolean appStarted = false;
private long loadTime = 0;

@NonNull
Expand All @@ -42,6 +51,7 @@ public String getName() {

public RNAdMobAppOpenAdModule(ReactApplicationContext reactContext) {
super(reactContext);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}

private void sendEvent(String eventName, @Nullable WritableMap data) {
Expand All @@ -58,6 +68,7 @@ public void onAdDismissedFullScreenContent() {
public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
if (presentPromise != null) {
presentPromise.reject(String.valueOf(adError.getCode()), adError.getMessage());
presentPromise = null;
}
WritableMap error = Arguments.createMap();
error.putInt("code", adError.getCode());
Expand All @@ -69,58 +80,107 @@ public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
public void onAdShowedFullScreenContent() {
if (presentPromise != null) {
presentPromise.resolve(null);
presentPromise = null;
}
sendEvent(AD_PRESENTED, null);
}
};

@ReactMethod
public void setUnitId(String unitId) {
this.unitId = unitId;
requestAd(null, null);
}

@ReactMethod
public void setOptions(ReadableMap options) {
requestOptions = options.getMap("requestOptions");
showOnAppForeground = options.getBoolean("showOnAppForeground");
showOnColdStart = options.getBoolean("showOnColdStart");
requestAd(null, null);
}

@ReactMethod
public void requestAd(int requestId, String unitId, ReadableMap requestOptions, final Promise promise) {
requestAd(requestOptions, promise);
}

@ReactMethod
public void presentAd(int requestId, final Promise promise) {
presentPromise = promise;
showAdIfAvailable();
}

private void requestAd(@Nullable ReadableMap requestOptions, @Nullable final Promise promise) {
if (unitId == null || this.requestOptions == null) return;
Activity activity = getCurrentActivity();
if (activity == null) {
promise.reject("E_NULL_ACTIVITY", "Interstitial ad attempted to load but the current Activity was null.");
if (promise != null) {
promise.reject("E_NULL_ACTIVITY", "App Open Ad attempted to load but the current Activity was null.");
}
return;
}
requestOptions = requestOptions != null ? requestOptions : this.requestOptions;
AdManagerAdRequest adRequest = RNAdMobCommon.buildAdRequest(requestOptions);
activity.runOnUiThread(() -> {
AdManagerAdRequest adRequest = RNAdMobCommon.buildAdRequest(requestOptions);
AppOpenAd.load(getReactApplicationContext(), unitId, adRequest, AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
new AppOpenAd.AppOpenAdLoadCallback() {
@Override
public void onAdLoaded(@NonNull AppOpenAd ad) {
ad.setFullScreenContentCallback(fullScreenContentCallback);
appOpenAd = ad;
loadTime = (new Date()).getTime();
promise.resolve(null);
if (promise != null) {
promise.resolve(null);
}

sendEvent(AD_LOADED, null);

if (!appStarted) {
appStarted = true;
if (showOnColdStart) {
showAdIfAvailable();
}
}
}

@Override
public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
promise.reject(String.valueOf(loadAdError.getCode()), loadAdError.getMessage());
if (promise != null) {
promise.reject(String.valueOf(loadAdError.getCode()), loadAdError.getMessage());
}

WritableMap error = Arguments.createMap();
error.putInt("code", loadAdError.getCode());
error.putString("message", loadAdError.getMessage());
sendEvent(AD_FAILED_TO_LOAD, error);

if (!appStarted) {
appStarted = true;
}
}
});
});
}

@ReactMethod
public void presentAd(int requestId, final Promise promise) {
presentPromise = promise;
private void showAdIfAvailable() {
Activity activity = getCurrentActivity();
if (activity == null) {
promise.reject("E_NULL_ACTIVITY", "App Open Ad attempted to load but the current Activity was null.");
if (presentPromise != null) {
presentPromise.reject("E_NULL_ACTIVITY", "App Open Ad attempted to load but the current Activity was null.");
presentPromise = null;
}
return;
}
activity.runOnUiThread(() -> {
if (appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4)) {
appOpenAd.show(activity);
} else {
promise.reject("E_AD_NOT_READY", "Ad is not ready.");
requestAd(null, null);
if (presentPromise != null) {
presentPromise.reject("E_AD_NOT_READY", "Ad is not ready.");
presentPromise = null;
}
}
});
}
Expand All @@ -131,4 +191,11 @@ private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
return (dateDifference < (numMilliSecondsPerHour * numHours));
}

@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onMoveToForeground() {
if (showOnAppForeground) {
showAdIfAvailable();
}
}

}
2 changes: 1 addition & 1 deletion docs/docs/api/AppOpenAd.md
Expand Up @@ -24,7 +24,7 @@ TODO
static createAd(unitId: string, showOnColdStart?: boolean, requestOptions?: RequestOptions): AppOpenAd
```

Creates an ad instance. You can create AppOpenAd only once in your app. Ad is loaded automatically after created and dismissed.
Creates an ad instance. If you create ad more than once, ad created before is destroyed. Ad is loaded automatically after created and dismissed.

**Parameters**

Expand Down

0 comments on commit e65a458

Please sign in to comment.