diff --git a/ChangeLog.txt b/ChangeLog.txt index b091e8226..835055df8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,5 +1,25 @@ Google Mobile Ads Unity Plugin Change Log +************** +Version 3.11.0 +************** + +Plugin: +- Updated Android ad events to be invoked on the main thread. +- Added `MobileAds.SetiOSAppPauseOnBackground()` method to pause iOS apps when +displaying full screen ads. +- Fixed issue were banners repositioned incorrectly following an orienation +change. + +Mediation packages: +- Added maio mediation support package. +- Added nend mediation support package. + +Built and tested with: +- Google Play services 11.8.0 +- Google Mobile Ads iOS SDK 7.27.0 +- Unity Jar Resolver 1.2.61.0 + ************** Version 3.10.0 ************** diff --git a/mediation/AppLovin/CHANGELOG.md b/mediation/AppLovin/CHANGELOG.md index f8cfbb9e6..602790498 100644 --- a/mediation/AppLovin/CHANGELOG.md +++ b/mediation/AppLovin/CHANGELOG.md @@ -1,7 +1,11 @@ # AppLovin Adapter plugin for Google Mobile Ads SDK for Unity 3D Changelog +## 1.1.0 +- Supports AppLovin Android SDK version 7.7.0. +- Supports AppLovin iOS SDK version 4.7.0. + ## 1.0.0 - First release! -- Supports Android adapter version 7.4.1.1. -- Supports iOS adapter version 4.4.1.1. +- Supports AppLovin Android SDK version 7.4.1. +- Supports AppLovin iOS SDK version 4.4.1. diff --git a/mediation/AppLovin/build.gradle b/mediation/AppLovin/build.gradle index b60e3b83d..0e28180be 100644 --- a/mediation/AppLovin/build.gradle +++ b/mediation/AppLovin/build.gradle @@ -23,7 +23,7 @@ project.ext { 'UNITY_EXE environment variable and point it to your Unity installation.') } - versionString = '1.0.0' + versionString = '1.1.0' pluginName = 'GoogleMobileAdsAppLovinMediation' pluginFileName = "${pluginName}.unitypackage" zipName = "${pluginName}-${versionString}" diff --git a/mediation/AppLovin/source/plugin/Assets/GoogleMobileAds/Editor/AppLovinMediationDependencies.xml b/mediation/AppLovin/source/plugin/Assets/GoogleMobileAds/Editor/AppLovinMediationDependencies.xml index 0d3407ea8..7e46cca41 100644 --- a/mediation/AppLovin/source/plugin/Assets/GoogleMobileAds/Editor/AppLovinMediationDependencies.xml +++ b/mediation/AppLovin/source/plugin/Assets/GoogleMobileAds/Editor/AppLovinMediationDependencies.xml @@ -1,17 +1,16 @@ - + - + - + https://github.com/CocoaPods/Specs - diff --git a/mediation/InMobi/build.gradle b/mediation/InMobi/build.gradle index 7b273a3ec..642f6b72a 100644 --- a/mediation/InMobi/build.gradle +++ b/mediation/InMobi/build.gradle @@ -46,6 +46,7 @@ task exportPackage(type: Exec) { "-logFile", "temp/unity.log", "-exportPackage", "Assets/GoogleMobileAds/Editor", + "Assets/Plugins", "${exportPath}", "-quit" diff --git a/mediation/InMobi/source/plugin/Assets/GoogleMobileAds/Plugins/Android/GoogleMobileAdsInMobiMediation/AndroidManifest.xml b/mediation/InMobi/source/plugin/Assets/Plugins/Android/GoogleMobileAdsInMobiMediation/AndroidManifest.xml similarity index 100% rename from mediation/InMobi/source/plugin/Assets/GoogleMobileAds/Plugins/Android/GoogleMobileAdsInMobiMediation/AndroidManifest.xml rename to mediation/InMobi/source/plugin/Assets/Plugins/Android/GoogleMobileAdsInMobiMediation/AndroidManifest.xml diff --git a/mediation/InMobi/source/plugin/Assets/GoogleMobileAds/Plugins/Android/GoogleMobileAdsInMobiMediation/project.properties b/mediation/InMobi/source/plugin/Assets/Plugins/Android/GoogleMobileAdsInMobiMediation/project.properties similarity index 100% rename from mediation/InMobi/source/plugin/Assets/GoogleMobileAds/Plugins/Android/GoogleMobileAdsInMobiMediation/project.properties rename to mediation/InMobi/source/plugin/Assets/Plugins/Android/GoogleMobileAdsInMobiMediation/project.properties diff --git a/mediation/Maio/CHANGELOG.md b/mediation/Maio/CHANGELOG.md new file mode 100644 index 000000000..b6ac736d8 --- /dev/null +++ b/mediation/Maio/CHANGELOG.md @@ -0,0 +1,7 @@ +# maio Adapter plugin for Google Mobile Ads SDK for Unity 3D Changelog + +## 1.0.0 + +- First release! +- Supports Android adapter version 1.0.6.0. +- Supports iOS adapter version 1.2.18.0. diff --git a/mediation/Maio/README.md b/mediation/Maio/README.md new file mode 100644 index 000000000..851f2d2f2 --- /dev/null +++ b/mediation/Maio/README.md @@ -0,0 +1,5 @@ +# maio Adapter plugin for Google Mobile Ads SDK for Unity 3D + +This is a plugin to be used in conjunction with the Google Mobile Ads SDK in +Google Play services. For requirements, instructions, and other info, see the +[maio Adapter Integration Guide](https://developers.google.com/admob/unity/mediation/maio). diff --git a/mediation/Maio/build.gradle b/mediation/Maio/build.gradle new file mode 100644 index 000000000..b94c6ccc2 --- /dev/null +++ b/mediation/Maio/build.gradle @@ -0,0 +1,145 @@ +/* +* Gradle file to build a Unity package to add maio mediation support to the Google Mobile Ads Unity plugin. +* Usage: ./gradlew exportPackage +*/ +plugins { + id "com.jfrog.bintray" version "1.7.3" +} + +defaultTasks 'exportPackage' + +// Project level variables. +project.ext { + unity_exe = System.getProperty("UNITY_EXE") + if (unity_exe == null || unity_exe.isEmpty()) { + unity_exe = System.getenv("UNITY_EXE") + } + if (unity_exe == null || unity_exe.isEmpty()) { + unity_exe = '/Applications/Unity/Unity.app/Contents/MacOS/Unity' + } + + if (!file(unity_exe).exists()) { + throw new GradleException('Unable to locate installation of Unity. Please create a ' + + 'UNITY_EXE environment variable and point it to your Unity installation.') + } + + versionString = '1.0.0' + pluginName = 'GoogleMobileAdsMaioMediation' + pluginFileName = "${pluginName}.unitypackage" + zipName = "${pluginName}-${versionString}" + zipFileName = "${zipName}.zip" + pluginSource = file('source/plugin').absolutePath + pluginBuildDir = file('temp/plugin-build-dir').absolutePath + buildPath = file('temp').absolutePath + exportPath = file(pluginFileName).absolutePath +} + +// Build unity package using through command line interface. +// Create new unity project with files in temporary build directory and export files to a unity package. +// Command line usage and arguments documented at http://docs.unity3d.com/Manual/CommandLineArguments.html. +task exportPackage(type: Exec) { + description = "Creates and exports the Plugin unity package" + executable "${unity_exe}" + args "-g.building", + "-batchmode", + "-projectPath", "${pluginBuildDir}", + "-logFile", "temp/unity.log", + "-exportPackage", + "Assets/GoogleMobileAds/Editor", + "Assets/Plugins", + "${exportPath}", + "-quit" + + ignoreExitValue true + + doLast { + if (execResult.getExitValue() != 0) { + copy { + from "temp/" + into "./" + include "unity.log" + } + } + } +} + +task createTempBuildFolder(type: Copy) { + from { "${pluginSource}" } + into { "${pluginBuildDir}" } +} + +task clearTempBuildFolder(type: Delete) { + delete { "${buildPath}" } +} + +exportPackage.dependsOn(createTempBuildFolder) +exportPackage.finalizedBy(clearTempBuildFolder) + +/** + * Delete task to delete any previously generated .zip files by makeZip task. + * makeZip depends on this task. + */ +task clearZip(type: Delete) { + // Targets to be deleted. + delete(zipFileName) +} + +/** + * Zip task to make a zip archive. This task depends on exportPackage and clearZip tasks. + */ +task makeZip(type: Zip) { + // Targets to be added to the zip archive. + from('./' + pluginFileName, './README.md', './CHANGELOG.md') + // Root directory name for the zip archive. + into(zipName) + // Name of the zip archive. + archiveName zipFileName + // Destination directory in which the archive needs to be saved. + destinationDir file('.') +} + +makeZip.dependsOn([clearZip, exportPackage]) +makeZip.mustRunAfter([clearZip, exportPackage]) + +/** + * Bintray closure needed to run the bintrayUpload task. + * + * Usage: + * ./gradlew bintrayUpload -PbintrayUser=YOUR_BINTRAY_USER_ID -PbintrayApiKey=YOUR_BINTRAY_API_KEY + * + * The Bintray User ID and API key can be added to your system environment variables as BINTRAY_USER + * and BINTRAY_API_KEY respectively, and the command can be reduced to: + * ./gradlew bintrayUpload + */ +bintray { + user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') + : System.getenv('BINTRAY_USER') + key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') + : System.getenv('BINTRAY_API_KEY') + + filesSpec { // 'filesSpec' is a standard Gradle CopySpec + from zipFileName + into "${pluginName}/${versionString}" + } + dryRun = false // Deploy after running. + publish = false // Don't auto publish after deploying. + override = false // Don't override existing version artifacts that are already published. + + pkg { + repo = 'mobile-ads-adapters-unity' + name = pluginName + userOrg = 'google' + desc = 'maio plugin for Google Mobile Ads Mediation.' + websiteUrl = 'https://developers.google.com/admob/unity/mediation/maio' + issueTrackerUrl = 'https://github.com/googleads/googleads-mobile-unity/issues' + vcsUrl = 'https://github.com/googleads/googleads-mobile-unity' + licenses = ['Apache-2.0'] + + version { + name = versionString + } + } +} + +bintrayUpload.dependsOn(makeZip) +bintrayUpload.mustRunAfter(makeZip) diff --git a/mediation/Maio/source/plugin/Assets/GoogleMobileAds/Editor/MaioMediationDependencies.xml b/mediation/Maio/source/plugin/Assets/GoogleMobileAds/Editor/MaioMediationDependencies.xml new file mode 100644 index 000000000..28690f55d --- /dev/null +++ b/mediation/Maio/source/plugin/Assets/GoogleMobileAds/Editor/MaioMediationDependencies.xml @@ -0,0 +1,22 @@ + + + + + https://jcenter.bintray.com/ + + + + + https://imobile-maio.github.io/maven + + + + + + + + https://github.com/CocoaPods/Specs + + + + diff --git a/mediation/Maio/source/plugin/Assets/Plugins/Android/GoogleMobileAdsMaioMediation/AndroidManifest.xml b/mediation/Maio/source/plugin/Assets/Plugins/Android/GoogleMobileAdsMaioMediation/AndroidManifest.xml new file mode 100644 index 000000000..49a05303c --- /dev/null +++ b/mediation/Maio/source/plugin/Assets/Plugins/Android/GoogleMobileAdsMaioMediation/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/mediation/Maio/source/plugin/Assets/Plugins/Android/GoogleMobileAdsMaioMediation/project.properties b/mediation/Maio/source/plugin/Assets/Plugins/Android/GoogleMobileAdsMaioMediation/project.properties new file mode 100644 index 000000000..3a387fb86 --- /dev/null +++ b/mediation/Maio/source/plugin/Assets/Plugins/Android/GoogleMobileAdsMaioMediation/project.properties @@ -0,0 +1,2 @@ +target=android-26 +android.library=true diff --git a/mediation/Nend/CHANGELOG.md b/mediation/Nend/CHANGELOG.md new file mode 100644 index 000000000..f4416428a --- /dev/null +++ b/mediation/Nend/CHANGELOG.md @@ -0,0 +1,7 @@ +# nend Adapter plugin for Google Mobile Ads SDK for Unity 3D Changelog + +## 1.0.0 + +- First release! +- Supports nend Android SDK version 4.0.2. +- Supports nend iOS SDK version 4.0.2. diff --git a/mediation/Nend/README.md b/mediation/Nend/README.md new file mode 100644 index 000000000..e198ee222 --- /dev/null +++ b/mediation/Nend/README.md @@ -0,0 +1,6 @@ +# nend Adapter plugin for Google Mobile Ads SDK for Unity 3D + +This is a plugin to be used in conjunction with the Google Mobile Ads SDK in +Google Play services. For requirements, instructions, and other info, see the +[nend Adapter Integration Guide](https://developers.google.com/admob/unity/mediation/nend). + diff --git a/mediation/Nend/build.gradle b/mediation/Nend/build.gradle new file mode 100644 index 000000000..0ce3b3a22 --- /dev/null +++ b/mediation/Nend/build.gradle @@ -0,0 +1,144 @@ +/* +* Gradle file to build a Unity package to add nend mediation support to the Google Mobile Ads Unity plugin. +* Usage: ./gradlew exportPackage +*/ +plugins { + id "com.jfrog.bintray" version "1.7.3" +} + +defaultTasks 'exportPackage' + +// Project level variables. +project.ext { + unity_exe = System.getProperty("UNITY_EXE") + if (unity_exe == null || unity_exe.isEmpty()) { + unity_exe = System.getenv("UNITY_EXE") + } + if (unity_exe == null || unity_exe.isEmpty()) { + unity_exe = '/Applications/Unity/Unity.app/Contents/MacOS/Unity' + } + + if (!file(unity_exe).exists()) { + throw new GradleException('Unable to locate installation of Unity. Please create a ' + + 'UNITY_EXE environment variable and point it to your Unity installation.') + } + + versionString = '1.0.0' + pluginName = 'GoogleMobileAdsNendMediation' + pluginFileName = "${pluginName}.unitypackage" + zipName = "${pluginName}-${versionString}" + zipFileName = "${zipName}.zip" + pluginSource = file('source/plugin').absolutePath + pluginBuildDir = file('temp/plugin-build-dir').absolutePath + buildPath = file('temp').absolutePath + exportPath = file(pluginFileName).absolutePath +} + +// Build unity package using through command line interface. +// Create new unity project with files in temporary build directory and export files to a unity package. +// Command line usage and arguments documented at http://docs.unity3d.com/Manual/CommandLineArguments.html. +task exportPackage(type: Exec) { + description = "Creates and exports the Plugin unity package" + executable "${unity_exe}" + args "-g.building", + "-batchmode", + "-projectPath", "${pluginBuildDir}", + "-logFile", "temp/unity.log", + "-exportPackage", + "Assets/GoogleMobileAds/Editor", + "${exportPath}", + "-quit" + + ignoreExitValue true + + doLast { + if (execResult.getExitValue() != 0) { + copy { + from "temp/" + into "./" + include "unity.log" + } + } + } +} + +task createTempBuildFolder(type: Copy) { + from { "${pluginSource}" } + into { "${pluginBuildDir}" } +} + +task clearTempBuildFolder(type: Delete) { + delete { "${buildPath}" } +} + +exportPackage.dependsOn(createTempBuildFolder) +exportPackage.finalizedBy(clearTempBuildFolder) + +/** + * Delete task to delete any previously generated .zip files by makeZip task. + * makeZip depends on this task. + */ +task clearZip(type: Delete) { + // Targets to be deleted. + delete(zipFileName) +} + +/** + * Zip task to make a zip archive. This task depends on exportPackage and clearZip tasks. + */ +task makeZip(type: Zip) { + // Targets to be added to the zip archive. + from('./' + pluginFileName, './README.md', './CHANGELOG.md') + // Root directory name for the zip archive. + into(zipName) + // Name of the zip archive. + archiveName zipFileName + // Destination directory in which the archive needs to be saved. + destinationDir file('.') +} + +makeZip.dependsOn([clearZip, exportPackage]) +makeZip.mustRunAfter([clearZip, exportPackage]) + +/** + * Bintray closure needed to run the bintrayUpload task. + * + * Usage: + * ./gradlew bintrayUpload -PbintrayUser=YOUR_BINTRAY_USER_ID -PbintrayApiKey=YOUR_BINTRAY_API_KEY + * + * The Bintray User ID and API key can be added to your system environment variables as BINTRAY_USER + * and BINTRAY_API_KEY respectively, and the command can be reduced to: + * ./gradlew bintrayUpload + */ +bintray { + user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') + : System.getenv('BINTRAY_USER') + key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') + : System.getenv('BINTRAY_API_KEY') + + filesSpec { // 'filesSpec' is a standard Gradle CopySpec + from zipFileName + into "${pluginName}/${versionString}" + } + dryRun = false // Deploy after running. + publish = false // Don't auto publish after deploying. + override = false // Don't override existing version artifacts that are already published. + + pkg { + repo = 'mobile-ads-adapters-unity' + name = pluginName + userOrg = 'google' + desc = 'nend plugin for Google Mobile Ads Mediation.' + websiteUrl = 'https://developers.google.com/admob/unity/mediation/nend' + issueTrackerUrl = 'https://github.com/googleads/googleads-mobile-unity/issues' + vcsUrl = 'https://github.com/googleads/googleads-mobile-unity' + licenses = ['Apache-2.0'] + + version { + name = versionString + } + } +} + +bintrayUpload.dependsOn(makeZip) +bintrayUpload.mustRunAfter(makeZip) diff --git a/mediation/Nend/source/plugin/Assets/GoogleMobileAds/Editor/NendMediationDependencies.xml b/mediation/Nend/source/plugin/Assets/GoogleMobileAds/Editor/NendMediationDependencies.xml new file mode 100644 index 000000000..9cdeab674 --- /dev/null +++ b/mediation/Nend/source/plugin/Assets/GoogleMobileAds/Editor/NendMediationDependencies.xml @@ -0,0 +1,23 @@ + + + + + https://jcenter.bintray.com/ + + + + + http://fan-adn.github.io/nendSDK-Android-lib/library + + + + + + + + https://github.com/CocoaPods/Specs + + + + + diff --git a/mediation/Tapjoy/CHANGELOG.md b/mediation/Tapjoy/CHANGELOG.md new file mode 100644 index 000000000..320285737 --- /dev/null +++ b/mediation/Tapjoy/CHANGELOG.md @@ -0,0 +1,7 @@ +# Tapjoy Adapter plugin for Google Mobile Ads SDK for Unity 3D Changelog + +## 1.0.0 + +- First release! +- Supports Tapjoy Android SDK version 11.11.1. +- Supports Tapjoy iOS SDK version 11.11.1. diff --git a/mediation/Tapjoy/README.md b/mediation/Tapjoy/README.md new file mode 100644 index 000000000..b873cab3b --- /dev/null +++ b/mediation/Tapjoy/README.md @@ -0,0 +1,6 @@ +# Tapjoy Adapter plugin for Google Mobile Ads SDK for Unity 3D + +This is a plugin to be used in conjunction with the Google Mobile Ads SDK in +Google Play services. For requirements, instructions, and other info, see the +[Tapjoy Adapter Integration Guide](https://developers.google.com/admob/unity/mediation/tapjoy). + diff --git a/mediation/Tapjoy/build.gradle b/mediation/Tapjoy/build.gradle index 43b480b58..7d02415c4 100644 --- a/mediation/Tapjoy/build.gradle +++ b/mediation/Tapjoy/build.gradle @@ -2,6 +2,9 @@ * Gradle file to build a Unity package to add Tapjoy mediation support to the Google Mobile Ads Unity plugin. * Usage: ./gradlew exportPackage */ +plugins { + id "com.jfrog.bintray" version "1.7.3" +} defaultTasks 'exportPackage' @@ -20,10 +23,15 @@ project.ext { 'UNITY_EXE environment variable and point it to your Unity installation.') } + versionString = '1.0.0' + pluginName = 'GoogleMobileAdsTapjoyMediation' + pluginFileName = "${pluginName}.unitypackage" + zipName = "${pluginName}-${versionString}" + zipFileName = "${zipName}.zip" pluginSource = file('source/plugin').absolutePath pluginBuildDir = file('temp/plugin-build-dir').absolutePath buildPath = file('temp').absolutePath - exportPath = file('GoogleMobileAdsTapjoyMediation.unitypackage').absolutePath + exportPath = file(pluginFileName).absolutePath } // Build unity package using through command line interface. @@ -66,3 +74,72 @@ task clearTempBuildFolder(type: Delete) { exportPackage.dependsOn(createTempBuildFolder) exportPackage.finalizedBy(clearTempBuildFolder) + +/** + * Delete task to delete any previously generated .zip files by makeZip task. + * makeZip depends on this task. + */ +task clearZip(type: Delete) { + // Targets to be deleted. + delete(zipFileName) +} + +/** + * Zip task to make a zip archive. This task depends on exportPackage and clearZip tasks. + */ +task makeZip(type: Zip) { + // Targets to be added to the zip archive. + from("./${pluginFileName}", "./README.md", "./CHANGELOG.md") + // Root directory name for the zip archive. + into(zipName) + // Name of the zip archive. + archiveName zipFileName + // Destination directory in which the archive needs to be saved. + destinationDir file('.') +} + +makeZip.dependsOn([clearZip, exportPackage]) +makeZip.mustRunAfter([clearZip, exportPackage]) + +/** + * Bintray closure needed to run the bintrayUpload task. + * + * Usage: + * ./gradlew bintrayUpload -PbintrayUser=YOUR_BINTRAY_USER_ID -PbintrayApiKey=YOUR_BINTRAY_API_KEY + * + * The Bintray User ID and API key can be added to your system environment variables as BINTRAY_USER + * and BINTRAY_API_KEY respectively, and the command can be reduced to: + * ./gradlew bintrayUpload + */ +bintray { + user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') + : System.getenv('BINTRAY_USER') + key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') + : System.getenv('BINTRAY_API_KEY') + + filesSpec { // 'filesSpec' is a standard Gradle CopySpec + from zipFileName + into "${pluginName}/${versionString}" + } + dryRun = false // Deploy after running. + publish = false // Don't auto publish after deploying. + override = false // Don't override existing version artifacts that are already published. + + pkg { + repo = 'mobile-ads-adapters-unity' + name = pluginName + userOrg = 'google' + desc = 'Tapjoy plugin for Google Mobile Ads Mediation.' + websiteUrl = 'https://developers.google.com/admob/unity/mediation/tapjoy' + issueTrackerUrl = 'https://github.com/googleads/googleads-mobile-unity/issues' + vcsUrl = 'https://github.com/googleads/googleads-mobile-unity' + licenses = ['Apache-2.0'] + + version { + name = versionString + } + } +} + +bintrayUpload.dependsOn(makeZip) +bintrayUpload.mustRunAfter(makeZip) diff --git a/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsDemoScript.cs b/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsDemoScript.cs index 4aab941ad..115b8f48b 100644 --- a/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsDemoScript.cs +++ b/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsDemoScript.cs @@ -29,6 +29,8 @@ public void Start() string appId = "unexpected_platform"; #endif + MobileAds.SetiOSAppPauseOnBackground(true); + // Initialize the Google Mobile Ads SDK. MobileAds.Initialize(appId); diff --git a/source/android-library/app/build.gradle b/source/android-library/app/build.gradle index f79ba7c24..681be6ed2 100644 --- a/source/android-library/app/build.gradle +++ b/source/android-library/app/build.gradle @@ -24,7 +24,7 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) api 'com.android.support:appcompat-v7:26.1.0' - api 'com.google.android.gms:play-services-ads:11.6.2' + api 'com.google.android.gms:play-services-ads:11.8.0' } task clearJar(type: Delete) { diff --git a/source/android-library/app/src/main/java/com/google/unity/ads/Banner.java b/source/android-library/app/src/main/java/com/google/unity/ads/Banner.java index b95641041..9dead1064 100644 --- a/source/android-library/app/src/main/java/com/google/unity/ads/Banner.java +++ b/source/android-library/app/src/main/java/com/google/unity/ads/Banner.java @@ -18,14 +18,13 @@ import android.app.Activity; import android.graphics.Color; import android.graphics.Point; -import android.os.Build; import android.util.Log; -import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.WindowManager; import android.widget.PopupWindow; + import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdSize; @@ -81,6 +80,12 @@ public class Banner { */ private UnityAdListener mUnityListener; + /** + * A {@code View.OnLayoutChangeListener} used to detect orientation changes and reposition + * banner ads as required. + */ + private View.OnLayoutChangeListener mLayoutChangeListener; + /** * Creates an instance of {@code Banner}. * @@ -182,6 +187,18 @@ public void onAdLeftApplication() { } } }); + + mLayoutChangeListener = new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + if (mPopupWindow.isShowing() && !mHidden) { + updatePosition(); + } + } + }; + mUnityPlayerActivity.getWindow().getDecorView().getRootView() + .addOnLayoutChangeListener(mLayoutChangeListener); } private void createPopupWindow() { @@ -280,10 +297,14 @@ public void run() { } } }); + + mUnityPlayerActivity.getWindow().getDecorView().getRootView() + .removeOnLayoutChangeListener(mLayoutChangeListener); } /** * Get {@link AdView} height. + * * @return the height of the {@link AdView}. */ public float getHeightInPixels() { @@ -292,6 +313,7 @@ public float getHeightInPixels() { /** * Get {@link AdView} width. + * * @return the width of the {@link AdView}. */ public float getWidthInPixels() { @@ -316,8 +338,8 @@ public void run() { /** * Updates the {@link AdView} position. * - * @param positionX Position of banner ad on the x axis. - * @param positionY Position of banner ad on the y axis. + * @param positionX Position of banner ad on the x axis. + * @param positionY Position of banner ad on the y axis. */ public void setPosition(final int positionX, final int positionY) { mUnityPlayerActivity.runOnUiThread(new Runnable() { @@ -335,7 +357,6 @@ public void run() { * Update the {@link AdView} position based on current parameters. */ private void updatePosition() { - if (mPopupWindow != null && mPopupWindow.isShowing()) { View anchorView = mUnityPlayerActivity.getWindow().getDecorView().getRootView(); Point location = getPositionInPixels(anchorView); @@ -351,6 +372,7 @@ private void updatePosition() { * Gets the location for the PopUp window based on the current position code / offset and ad * view size. The location is in bottom left coordinate system as per the showAsDropDown and * update methods requirements. + * * @param anchorView the anchorview to position against. * @return the position point in pixels in the bottom left coordinate system. */ diff --git a/source/plugin/Assets/GoogleMobileAds/Api/AdLoader.cs b/source/plugin/Assets/GoogleMobileAds/Api/AdLoader.cs index 497a3e082..a1f319e0a 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/AdLoader.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/AdLoader.cs @@ -45,12 +45,14 @@ private AdLoader(Builder builder) BindingFlags.Static | BindingFlags.Public); this.adLoaderClient = (IAdLoaderClient)method.Invoke(null, new object[] { this }); + Utils.CheckInitialization(); + this.adLoaderClient.OnCustomNativeTemplateAdLoaded += delegate (object sender, CustomNativeEventArgs args) { if (this.OnCustomNativeTemplateAdLoaded != null) { - this.OnCustomNativeTemplateAdLoaded(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnCustomNativeTemplateAdLoaded(this, args)); } }; this.adLoaderClient.OnAdFailedToLoad += delegate ( @@ -58,7 +60,7 @@ private AdLoader(Builder builder) { if (this.OnAdFailedToLoad != null) { - this.OnAdFailedToLoad(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdFailedToLoad(this, args)); } }; } diff --git a/source/plugin/Assets/GoogleMobileAds/Api/AdRequest.cs b/source/plugin/Assets/GoogleMobileAds/Api/AdRequest.cs index 6191f4015..7df70a666 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/AdRequest.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/AdRequest.cs @@ -21,7 +21,7 @@ namespace GoogleMobileAds.Api { public class AdRequest { - public const string Version = "3.10.0"; + public const string Version = "3.11.0"; public const string TestDeviceSimulator = "SIMULATOR"; private AdRequest(Builder builder) diff --git a/source/plugin/Assets/GoogleMobileAds/Api/BannerView.cs b/source/plugin/Assets/GoogleMobileAds/Api/BannerView.cs index d9cf299bc..fa917ea46 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/BannerView.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/BannerView.cs @@ -34,6 +34,7 @@ public BannerView(string adUnitId, AdSize adSize, AdPosition position) this.client = (IBannerClient)method.Invoke(null, null); client.CreateBannerView(adUnitId, adSize, position); + Utils.CheckInitialization(); ConfigureBannerEvents(); } @@ -48,6 +49,7 @@ public BannerView(string adUnitId, AdSize adSize, int x, int y) this.client = (IBannerClient)method.Invoke(null, null); client.CreateBannerView(adUnitId, adSize, x, y); + Utils.CheckInitialization(); ConfigureBannerEvents(); } @@ -116,7 +118,7 @@ private void ConfigureBannerEvents() { if (this.OnAdLoaded != null) { - this.OnAdLoaded(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLoaded(this, args)); } }; @@ -124,7 +126,7 @@ private void ConfigureBannerEvents() { if (this.OnAdFailedToLoad != null) { - this.OnAdFailedToLoad(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdFailedToLoad(this, args)); } }; @@ -132,7 +134,7 @@ private void ConfigureBannerEvents() { if (this.OnAdOpening != null) { - this.OnAdOpening(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdOpening(this, args)); } }; @@ -140,7 +142,7 @@ private void ConfigureBannerEvents() { if (this.OnAdClosed != null) { - this.OnAdClosed(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdClosed(this, args)); } }; @@ -148,7 +150,7 @@ private void ConfigureBannerEvents() { if (this.OnAdLeavingApplication != null) { - this.OnAdLeavingApplication(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLeavingApplication(this, args)); } }; } diff --git a/source/plugin/Assets/GoogleMobileAds/Api/InterstitialAd.cs b/source/plugin/Assets/GoogleMobileAds/Api/InterstitialAd.cs index 1312a0758..68039c707 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/InterstitialAd.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/InterstitialAd.cs @@ -34,45 +34,46 @@ public InterstitialAd(string adUnitId) this.client = (IInterstitialClient)method.Invoke(null, null); client.CreateInterstitialAd(adUnitId); + Utils.CheckInitialization(); this.client.OnAdLoaded += (sender, args) => + { + if (this.OnAdLoaded != null) { - if(this.OnAdLoaded != null) - { - this.OnAdLoaded(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLoaded(this, args)); + } + }; this.client.OnAdFailedToLoad += (sender, args) => + { + if (this.OnAdFailedToLoad != null) { - if(this.OnAdFailedToLoad != null) - { - this.OnAdFailedToLoad(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdFailedToLoad(this, args)); + } + }; this.client.OnAdOpening += (sender, args) => + { + if (this.OnAdOpening != null) { - if(this.OnAdOpening != null) - { - this.OnAdOpening(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdOpening(this, args)); + } + }; this.client.OnAdClosed += (sender, args) => + { + if (this.OnAdClosed != null) { - if(this.OnAdClosed != null) - { - this.OnAdClosed(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdClosed(this, args)); + } + }; this.client.OnAdLeavingApplication += (sender, args) => + { + if (this.OnAdLeavingApplication != null) { - if(this.OnAdLeavingApplication != null) - { - this.OnAdLeavingApplication(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLeavingApplication(this, args)); + } + }; } // These are the ad callback events that can be hooked into. diff --git a/source/plugin/Assets/GoogleMobileAds/Api/MobileAds.cs b/source/plugin/Assets/GoogleMobileAds/Api/MobileAds.cs index cdd36254c..16bb4081a 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/MobileAds.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/MobileAds.cs @@ -26,6 +26,7 @@ public class MobileAds public static void Initialize(string appId) { client.Initialize(appId); + MobileAdsEventExecutor.Initialize(); } public static void SetApplicationMuted(bool muted) @@ -38,6 +39,11 @@ public static void SetApplicationVolume(float volume) client.SetApplicationVolume(volume); } + public static void SetiOSAppPauseOnBackground(bool pause) + { + client.SetiOSAppPauseOnBackground(pause); + } + private static IMobileAdsClient GetMobileAdsClient() { Type googleMobileAdsClientFactory = Type.GetType( diff --git a/source/plugin/Assets/GoogleMobileAds/Api/NativeExpressAdView.cs b/source/plugin/Assets/GoogleMobileAds/Api/NativeExpressAdView.cs index f9dc4a8dd..2d6c4c241 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/NativeExpressAdView.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/NativeExpressAdView.cs @@ -34,6 +34,7 @@ public NativeExpressAdView(string adUnitId, AdSize adSize, AdPosition position) this.client = (INativeExpressAdClient)method.Invoke(null, null); this.client.CreateNativeExpressAdView(adUnitId, adSize, position); + Utils.CheckInitialization(); ConfigureNativeExpressAdEvents(); } @@ -48,6 +49,7 @@ public NativeExpressAdView(string adUnitId, AdSize adSize, int x, int y) this.client = (INativeExpressAdClient)method.Invoke(null, null); this.client.CreateNativeExpressAdView(adUnitId, adSize, x, y); + Utils.CheckInitialization(); ConfigureNativeExpressAdEvents(); } @@ -90,41 +92,41 @@ private void ConfigureNativeExpressAdEvents() { this.client.OnAdLoaded += (sender, args) => { - if(this.OnAdLoaded != null) + if (this.OnAdLoaded != null) { - this.OnAdLoaded(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLoaded(this, args)); } }; this.client.OnAdFailedToLoad += (sender, args) => { - if(this.OnAdFailedToLoad != null) + if (this.OnAdFailedToLoad != null) { - this.OnAdFailedToLoad(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdFailedToLoad(this, args)); } }; this.client.OnAdOpening += (sender, args) => { - if(this.OnAdOpening != null) + if (this.OnAdOpening != null) { - this.OnAdOpening(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdOpening(this, args)); } }; this.client.OnAdClosed += (sender, args) => { - if(this.OnAdClosed != null) + if (this.OnAdClosed != null) { - this.OnAdClosed(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdClosed(this, args)); } }; this.client.OnAdLeavingApplication += (sender, args) => { - if(this.OnAdLeavingApplication != null) + if (this.OnAdLeavingApplication != null) { - this.OnAdLeavingApplication(this, args); + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLeavingApplication(this, args)); } }; } diff --git a/source/plugin/Assets/GoogleMobileAds/Api/RewardBasedVideoAd.cs b/source/plugin/Assets/GoogleMobileAds/Api/RewardBasedVideoAd.cs index c31c6df96..9da3064d8 100644 --- a/source/plugin/Assets/GoogleMobileAds/Api/RewardBasedVideoAd.cs +++ b/source/plugin/Assets/GoogleMobileAds/Api/RewardBasedVideoAd.cs @@ -43,61 +43,62 @@ private RewardBasedVideoAd() this.client = (IRewardBasedVideoAdClient)method.Invoke(null, null); client.CreateRewardBasedVideoAd(); + Utils.CheckInitialization(); this.client.OnAdLoaded += (sender, args) => + { + if (this.OnAdLoaded != null) { - if (this.OnAdLoaded != null) - { - this.OnAdLoaded(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLoaded(this, args)); + } + }; this.client.OnAdFailedToLoad += (sender, args) => + { + if (this.OnAdFailedToLoad != null) { - if (this.OnAdFailedToLoad != null) - { - this.OnAdFailedToLoad(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdFailedToLoad(this, args)); + } + }; this.client.OnAdOpening += (sender, args) => + { + if (this.OnAdOpening != null) { - if (this.OnAdOpening != null) - { - this.OnAdOpening(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdOpening(this, args)); + } + }; this.client.OnAdStarted += (sender, args) => + { + if (this.OnAdStarted != null) { - if (this.OnAdStarted != null) - { - this.OnAdStarted(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdStarted(this, args)); + } + }; this.client.OnAdClosed += (sender, args) => + { + if (this.OnAdClosed != null) { - if (this.OnAdClosed != null) - { - this.OnAdClosed(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdClosed(this, args)); + } + }; this.client.OnAdLeavingApplication += (sender, args) => + { + if (this.OnAdLeavingApplication != null) { - if (this.OnAdLeavingApplication != null) - { - this.OnAdLeavingApplication(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdLeavingApplication(this, args)); + } + }; this.client.OnAdRewarded += (sender, args) => + { + if (this.OnAdRewarded != null) { - if (this.OnAdRewarded != null) - { - this.OnAdRewarded(this, args); - } - }; + MobileAdsEventExecutor.executeInUpdate(() => this.OnAdRewarded(this, args)); + } + }; } // These are the ad callback events that can be hooked into. diff --git a/source/plugin/Assets/GoogleMobileAds/Common/DummyClient.cs b/source/plugin/Assets/GoogleMobileAds/Common/DummyClient.cs index 63da6acfc..b1d084354 100644 --- a/source/plugin/Assets/GoogleMobileAds/Common/DummyClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Common/DummyClient.cs @@ -29,7 +29,7 @@ public DummyClient() } // Disable warnings for unused dummy ad events. - #pragma warning disable 67 +#pragma warning disable 67 public event EventHandler OnAdLoaded; @@ -47,7 +47,7 @@ public DummyClient() public event EventHandler OnCustomNativeTemplateAdLoaded; - #pragma warning restore 67 +#pragma warning restore 67 public string UserId { @@ -78,6 +78,11 @@ public void SetApplicationVolume(float volume) Debug.Log("Dummy " + MethodBase.GetCurrentMethod().Name); } + public void SetiOSAppPauseOnBackground(bool pause) + { + Debug.Log("Dummy " + MethodBase.GetCurrentMethod().Name); + } + public void CreateBannerView(string adUnitId, AdSize adSize, AdPosition position) { Debug.Log("Dummy " + MethodBase.GetCurrentMethod().Name); diff --git a/source/plugin/Assets/GoogleMobileAds/Common/IMobileAdsClient.cs b/source/plugin/Assets/GoogleMobileAds/Common/IMobileAdsClient.cs index 1f6226869..b808e0222 100644 --- a/source/plugin/Assets/GoogleMobileAds/Common/IMobileAdsClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Common/IMobileAdsClient.cs @@ -29,5 +29,8 @@ public interface IMobileAdsClient // all ads. Use this method only if your application has its own volume controls // (e.g., custom music or sound effect muting). Defaults to false. void SetApplicationMuted(bool muted); + + // Set whether an iOS app should pause when a full screen ad is displayed. + void SetiOSAppPauseOnBackground(bool pause); } } diff --git a/source/plugin/Assets/GoogleMobileAds/Common/MobileAdsEventExecutor.cs b/source/plugin/Assets/GoogleMobileAds/Common/MobileAdsEventExecutor.cs new file mode 100644 index 000000000..54baa03fe --- /dev/null +++ b/source/plugin/Assets/GoogleMobileAds/Common/MobileAdsEventExecutor.cs @@ -0,0 +1,91 @@ +// Copyright (C) 2018 Google, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; + +using UnityEngine; + +namespace GoogleMobileAds.Common +{ + internal class MobileAdsEventExecutor : MonoBehaviour + { + private static MobileAdsEventExecutor instance = null; + + private static List adEventsQueue = new List(); + + private volatile static bool adEventsQueueEmpty = true; + + public static void Initialize() + { + if (IsActive()) + { + return; + } + + // Add an invisible game object to the scene + GameObject obj = new GameObject("MobileAdsMainThreadExecuter"); + obj.hideFlags = HideFlags.HideAndDontSave; + DontDestroyOnLoad(obj); + instance = obj.AddComponent(); + } + + public static bool IsActive() + { + return instance != null; + } + + public void Awake() + { + DontDestroyOnLoad(gameObject); + } + + public static void executeInUpdate(Action action) + { + lock (adEventsQueue) + { + adEventsQueue.Add(action); + adEventsQueueEmpty = false; + } + } + + public void Update() + { + if (adEventsQueueEmpty) + { + return; + } + + List stagedAdEventsQueue = new List(); + + lock (adEventsQueue) + { + stagedAdEventsQueue.AddRange(adEventsQueue); + adEventsQueue.Clear(); + adEventsQueueEmpty = true; + } + + foreach (Action stagedEvent in stagedAdEventsQueue) + { + stagedEvent.Invoke(); + } + } + + public void OnDisable() + { + instance = null; + } + } +} \ No newline at end of file diff --git a/source/plugin/Assets/GoogleMobileAds/Common/MobileAdsEventExecutor.cs.meta b/source/plugin/Assets/GoogleMobileAds/Common/MobileAdsEventExecutor.cs.meta new file mode 100644 index 000000000..ec47570a1 --- /dev/null +++ b/source/plugin/Assets/GoogleMobileAds/Common/MobileAdsEventExecutor.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: d5dfa1423353e45c9bb636c123e5a05a +timeCreated: 1517530267 +licenseType: Pro +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/plugin/Assets/GoogleMobileAds/Common/Utils.cs b/source/plugin/Assets/GoogleMobileAds/Common/Utils.cs index a0cf70c81..a9730554c 100644 --- a/source/plugin/Assets/GoogleMobileAds/Common/Utils.cs +++ b/source/plugin/Assets/GoogleMobileAds/Common/Utils.cs @@ -21,6 +21,17 @@ namespace GoogleMobileAds.Common { internal class Utils { + public static void CheckInitialization() + { + if (!MobileAdsEventExecutor.IsActive()) + { + Debug.Log("You intitialized an ad object but have not yet called MobileAds.Initialize(). We " + + "highly recommend you call MobileAds.Initialize() before interacting with the Google " + + "Mobile Ads SDK."); + } + MobileAdsEventExecutor.Initialize(); + } + public static Texture2D GetTexture2DFromByteArray(byte[] img) { // Create a texture. Texture size does not matter, since diff --git a/source/plugin/Assets/GoogleMobileAds/Editor/GoogleMobileAdsDependencies.xml b/source/plugin/Assets/GoogleMobileAds/Editor/GoogleMobileAdsDependencies.xml index d1434da53..97438d585 100644 --- a/source/plugin/Assets/GoogleMobileAds/Editor/GoogleMobileAdsDependencies.xml +++ b/source/plugin/Assets/GoogleMobileAds/Editor/GoogleMobileAdsDependencies.xml @@ -1,6 +1,6 @@ - + https://maven.google.com diff --git a/source/plugin/Assets/GoogleMobileAds/Platforms/Android/AdLoaderClient.cs b/source/plugin/Assets/GoogleMobileAds/Platforms/Android/AdLoaderClient.cs index d491ce340..f0355add8 100644 --- a/source/plugin/Assets/GoogleMobileAds/Platforms/Android/AdLoaderClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Platforms/Android/AdLoaderClient.cs @@ -84,7 +84,8 @@ public void onCustomClick(AndroidJavaObject ad, string assetName) { CustomNativeTemplateAd nativeAd = new CustomNativeTemplateAd( new CustomNativeTemplateClient(ad)); - this.CustomNativeTemplateCallbacks[nativeAd.GetCustomTemplateId()](nativeAd, assetName); + MobileAdsEventExecutor.executeInUpdate(() => + this.CustomNativeTemplateCallbacks[nativeAd.GetCustomTemplateId()](nativeAd, assetName)); } } } diff --git a/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs b/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs index 0b229db05..392fe8355 100644 --- a/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs @@ -54,6 +54,11 @@ public void SetApplicationMuted(bool muted) AndroidJavaClass mobileAdsClass = new AndroidJavaClass(Utils.MobileAdsClassName); mobileAdsClass.CallStatic("setAppMuted", muted); } + + public void SetiOSAppPauseOnBackground(bool pause) + { + // Do nothing on Android. Default behavior is to pause when app is backgrounded. + } } } diff --git a/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/CustomNativeTemplateClient.cs b/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/CustomNativeTemplateClient.cs index 862e6c37f..67d0e9887 100644 --- a/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/CustomNativeTemplateClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/CustomNativeTemplateClient.cs @@ -145,7 +145,7 @@ private static void NativeCustomTemplateDidReceiveClickCallback( if (client.clickHandler != null) { CustomNativeTemplateAd nativeAd = new CustomNativeTemplateAd(client); - client.clickHandler(nativeAd, assetName); + MobileAdsEventExecutor.executeInUpdate(() => client.clickHandler(nativeAd, assetName)); } } diff --git a/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/Externs.cs b/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/Externs.cs index 8b0fc5cfa..35f650b22 100644 --- a/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/Externs.cs +++ b/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/Externs.cs @@ -33,6 +33,9 @@ internal class Externs [DllImport("__Internal")] internal static extern void GADUSetApplicationMuted(bool muted); + [DllImport("__Internal")] + internal static extern void GADUSetiOSAppPauseOnBackground(bool pause); + [DllImport("__Internal")] internal static extern IntPtr GADUCreateRequest(); diff --git a/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/MobileAdsClient.cs b/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/MobileAdsClient.cs index 9e3182ec4..6d9085f90 100644 --- a/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/MobileAdsClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Platforms/iOS/MobileAdsClient.cs @@ -48,6 +48,11 @@ public void SetApplicationMuted(bool muted) { Externs.GADUSetApplicationMuted(muted); } + + public void SetiOSAppPauseOnBackground(bool pause) + { + Externs.GADUSetiOSAppPauseOnBackground(pause); + } } } diff --git a/source/plugin/Assets/Plugins/iOS/GADUInterface.m b/source/plugin/Assets/Plugins/iOS/GADUInterface.m index da629b54d..884e7ecf3 100644 --- a/source/plugin/Assets/Plugins/iOS/GADUInterface.m +++ b/source/plugin/Assets/Plugins/iOS/GADUInterface.m @@ -4,6 +4,7 @@ #import "GADUBanner.h" #import "GADUInterstitial.h" #import "GADUNativeCustomTemplateAd.h" +#import "GADUPluginUtil.h" #import "GADUAdNetworkExtras.h" #import "GADUNativeExpressAd.h" #import "GADUObjectCache.h" @@ -66,6 +67,10 @@ void GADUSetApplicationMuted(BOOL muted) { [[GADMobileAds sharedInstance] setApplicationMuted:muted]; } +// Indicates if the Unity app should be paused when a full screen ad (interstitial +// or rewarded video ad) is displayed. +void GADUSetiOSAppPauseOnBackground(BOOL pause) { [GADUPluginUtil setPauseOnBackground:pause]; } + /// Creates a GADBannerView with the specified width, height, and position. Returns a reference to /// the GADUBannerView. GADUTypeBannerRef GADUCreateBannerView(GADUTypeBannerClientRef *bannerClient, const char *adUnitID, @@ -510,7 +515,7 @@ void GADURequestNativeAd(GADUTypeAdLoaderRef adLoader, GADUTypeRequestRef reques (__bridge GADUNativeCustomTemplateAd *)nativeCustomTemplateAd; NSData *imageData = UIImageJPEGRepresentation( [internalNativeCustomTemplateAd imageForKey:GADUStringFromUTF8String(key)], 0.0); - NSString *base64String = [imageData base64Encoding]; + NSString *base64String = [imageData base64EncodedStringWithOptions:nil]; return cStringCopy(base64String.UTF8String); } diff --git a/source/plugin/Assets/Plugins/iOS/GADUInterstitial.m b/source/plugin/Assets/Plugins/iOS/GADUInterstitial.m index 0a8bed275..5e98a1946 100644 --- a/source/plugin/Assets/Plugins/iOS/GADUInterstitial.m +++ b/source/plugin/Assets/Plugins/iOS/GADUInterstitial.m @@ -66,6 +66,10 @@ - (void)interstitial:(GADInterstitial *)ad didFailToReceiveAdWithError:(GADReque } - (void)interstitialWillPresentScreen:(GADInterstitial *)ad { + if ([GADUPluginUtil pauseOnBackground]) { + UnityPause(YES); + } + if (self.willPresentCallback) { self.willPresentCallback(self.interstitialClient); } @@ -76,6 +80,10 @@ - (void)interstitialWillDismissScreen:(GADInterstitial *)ad { } - (void)interstitialDidDismissScreen:(GADInterstitial *)ad { + if (UnityIsPaused()) { + UnityPause(NO); + } + if (self.didDismissCallback) { self.didDismissCallback(self.interstitialClient); } diff --git a/source/plugin/Assets/Plugins/iOS/GADUNativeCustomTemplateAd.m b/source/plugin/Assets/Plugins/iOS/GADUNativeCustomTemplateAd.m index 37c537059..2b2cbdd0e 100644 --- a/source/plugin/Assets/Plugins/iOS/GADUNativeCustomTemplateAd.m +++ b/source/plugin/Assets/Plugins/iOS/GADUNativeCustomTemplateAd.m @@ -25,13 +25,13 @@ - (UIImage *)imageForKey:(NSString *)key { } - (void)performClickOnAssetWithKey:(NSString *)key withCustomClickAction:(bool)customClickAction { - dispatch_block_t clickHandler = nil; if (customClickAction) { - clickHandler = ^{ - [self didReceiveClickForAsset:key]; - }; + __weak GADUNativeCustomTemplateAd *weakSelf = self; + [self.nativeCustomTemplateAd setCustomClickHandler:^(NSString *assetID){ + [weakSelf didReceiveClickForAsset:key]; + }]; } - [self.nativeCustomTemplateAd performClickOnAssetWithKey:key customClickHandler:clickHandler]; + [self.nativeCustomTemplateAd performClickOnAssetWithKey:key]; } - (void)didReceiveClickForAsset:(NSString *)key { diff --git a/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.h b/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.h index c3361b2e4..b96602ce2 100644 --- a/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.h +++ b/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.h @@ -8,6 +8,9 @@ @interface GADUPluginUtil : NSObject +/// Whether the Unity app should be paused when a full screen ad is displayed. +@property(class) BOOL pauseOnBackground; + /// Returns the Unity view controller. + (UIViewController *)unityGLViewController; diff --git a/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.m b/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.m index d15419dcb..a1aefb6dc 100644 --- a/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.m +++ b/source/plugin/Assets/Plugins/iOS/GADUPluginUtil.m @@ -33,6 +33,16 @@ static CGFloat FullSafeWidthLandscape(void) { @implementation GADUPluginUtil +static BOOL _pauseOnBackground = NO; + ++ (BOOL)pauseOnBackground { + return _pauseOnBackground; +} + ++ (void)setPauseOnBackground:(BOOL)pause { + _pauseOnBackground = pause; +} + + (GADAdSize)safeAdSizeForAdSize:(GADAdSize)adSize { if (IsOperatingSystemAtLeastVersion(11) && GADAdSizeEqualToSize(kGADAdSizeSmartBannerLandscape, adSize)) { diff --git a/source/plugin/Assets/Plugins/iOS/GADURewardBasedVideoAd.m b/source/plugin/Assets/Plugins/iOS/GADURewardBasedVideoAd.m index c65b54415..418bc8b59 100644 --- a/source/plugin/Assets/Plugins/iOS/GADURewardBasedVideoAd.m +++ b/source/plugin/Assets/Plugins/iOS/GADURewardBasedVideoAd.m @@ -19,7 +19,7 @@ + (UIViewController *)unityGLViewController { } - (instancetype)initWithRewardBasedVideoClientReference: - (GADUTypeRewardBasedVideoAdClientRef *)rewardBasedVideoAdClient { + (GADUTypeRewardBasedVideoAdClientRef *)rewardBasedVideoAdClient { self = [super init]; if (self) { _rewardBasedVideoAdClient = rewardBasedVideoAdClient; @@ -72,6 +72,10 @@ - (void)rewardBasedVideoAd:(GADRewardBasedVideoAd *)rewardBasedVideoAd } - (void)rewardBasedVideoAdDidOpen:(GADRewardBasedVideoAd *)rewardBasedVideoAd { + if ([GADUPluginUtil pauseOnBackground]) { + UnityPause(YES); + } + if (self.didOpenCallback) { self.didOpenCallback(self.rewardBasedVideoAdClient); } @@ -84,6 +88,10 @@ - (void)rewardBasedVideoAdDidStartPlaying:(GADRewardBasedVideoAd *)rewardBasedVi } - (void)rewardBasedVideoAdDidClose:(GADRewardBasedVideoAd *)rewardBasedVideoAd { + if (UnityIsPaused()) { + UnityPause(NO); + } + if (self.didCloseCallback) { self.didCloseCallback(self.rewardBasedVideoAdClient); }