Skip to content

Commit

Permalink
Child protection (#1)
Browse files Browse the repository at this point in the history
* Extensions

* Edit Native Ad Unit

* Fix extras for Native

* Add check localExtras on Native Ad

* NPA & Mopub consent

* Cleam code

* Add child protection doc & Edit Readme

* Change readme

* Change version

* Change document
  • Loading branch information
yilmazgokhan authored Sep 15, 2021
1 parent 7d15ac5 commit e0b6a1e
Show file tree
Hide file tree
Showing 18 changed files with 604 additions and 431 deletions.
Binary file added Huawei_Mopub_Mediation_Child_Protection.pdf
Binary file not shown.
92 changes: 75 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Huawei-Mopub Mediation Github Documentation

<h1 align="center">Huawei-Mopub Mediation Github Documentation</h3>
![Latest Version](https://img.shields.io/badge/latestVersion-1.2.0-yellow) ![Kotlin](https://img.shields.io/badge/language-kotlin-blue)

This is a project to demonstrate how to use MoPub’s mediation feature with Huawei Ads Kit.

Expand Down Expand Up @@ -36,16 +37,67 @@ This is a project to demonstrate how to use MoPub’s mediation feature with Hua
| Native Ad (Advanced) | com.hmscl.huawei.ads.mediation_adapter_mopub.native_advanced |

## Custom Event Parameters

### Banner, Interstitial, Rewarded
```
{
"adUnitID": "111", <-- Required
"appid":"222",
"tagForChildProtection": "false",
"tagUnderAgeOfPromise": "false",
"tagAdContentClassification": "false",
"tagConsentString": "false",
}
```

### Native
```
{
"adUnitID": "222", <-- Required
"appid":"111",
"tagForChildDirectedTreatment": "false",
"TAG_FOR_UNDER_AGE_OF_CONSENT_KEY": "false",
"contentUrl" : "abc"
"adUnitID": "111", <-- Required
"appid":"222",
"tagForChildProtection": "false",
"tagUnderAgeOfPromise": "false",
"tagAdContentClassification": "false",
"tagConsentString": "false",
"orientation_preference" : "1"
"ad_choices_placement" : "1"
"swap_margins" : "1"
}
```
Other values are optional

### Parameters Description
| Key | Description | Possible value |
| --- | --- | --- |
| adUnitID | Huawei Ads Unit ID | String |
| appid | Huawei Ads App ID | String |
| tagForChildProtection | Sets the tag for child-directed content, to comply with the Children's Online Privacy Protection Act (COPPA). | <ul><li>`true`: You want your ad content to be COPPA-compliant (interest-based ads and remarketing ads will be disabled for the ad request). </li><li>`false`: You do not want your ad content to be COPPA-compliant. </li></ul> |
| tagUnderAgeOfPromise | Sets the tag for users in the European Economic Area (EEA) under the age of consent, to comply with the General Data Protection Regulation (GDPR). Ad requests with this tag enabled will be unable to obtain personalized ads. | <ul><li> `true`: You want the ad request to meet the ad standard for users under the age of consent. </li><li> `false`: You do not want the ad request to meet the ad standard for users under the age of consent. </li></ul> |
| tagAdContentClassification | Sets the maximum ad content rating for the ad requests of your app. The ads obtained using this method have a content rating at or below the specified one. | <ul><li> `w`: content suitable for widespread audiences. </li><li> `pi`: content suitable for audiences under parental instructions. </li><li> `j`: content suitable for junior and older audiences. </li><li> `a`: content suitable only for adults. </li></ul> |
| tagConsentString | Sets the user consent string that complies with TCF 2.0. | String |
| orientation_preference (Native specific) | Sets the orientation of an ad image. | <ul><li> `0`: ANY </li><li> `1`: PORTRAIT </li><li> `2`: LANDSCAPE </li></ul> |
| ad_choices_placement (Native specific) | Sets the AdChoices icon position | <ul><li> `0`: TOP_LEFT </li><li> `1`: TOP_RIGHT </li><li> `2`: BOTTOM_RIGHT </li><li> `3`: BOTTOM_LEFT </li></ul> |
| swap_margins (Native specific) | Configure margin | <ul><li> `true`: Set margin on </li><li> `false`: Set margin off </li></ul> |

> Note: All values ​​must be String format.
Also all values can be set dynamically.

```
moPubNative.setLocalExtras(
mapOf(
TAG_FOR_CHILD_PROTECTION_KEY to true,
TAG_FOR_UNDER_AGE_OF_PROMISE_KEY to true,
TAG_FOR_AD_CONTENT_CLASSIFICATION_KEY to true,
TAG_CONSENT_STRING to "TCF 2.0 String",
KEY_EXTRA_ORIENTATION_PREFERENCE to 1,
KEY_EXTRA_AD_CHOICES_PLACEMENT to 1,
KEY_EXPERIMENTAL_EXTRA_SWAP_MARGINS to 1
)
)
```
> Note: Be aware that custom events parameters in Mopub platform will override your code side changes on the parameters.
[Mediation Child Protection Document](https://github.com/Explore-In-HMS/huawei.ads.mopub_mediation/blob/main/Huawei_Mopub_Mediation_Child_Protection.pdf)

# Integrate the Huawei Mediation SDK

Expand Down Expand Up @@ -73,7 +125,7 @@ In the app-level build.gradle, include Huawei Ads dependency (required by the ad
```groovy
dependencies {
implementation 'com.huawei.hms:ads:3.4.41.304'
implementation 'com.github.Explore-In-HMS:huawei.ads.mopub_mediation:1.1.0'
implementation 'com.github.Explore-In-HMS:huawei.ads.mopub_mediation:<latest_version>'
}
```
**Important:**: To add Huawei Ads Kit SDK and Mediation adapter to the cross platforms apps, the native project should be opened with Android Studio.
Expand Down Expand Up @@ -253,58 +305,64 @@ Huawei Ads can still be used on Cordova, for implementation click [here](https:/

# Screenshots

## MoPub
## MoPub Ads
<table>
<tr>
<td>
<img src="https://user-images.githubusercontent.com/41696219/109938644-51652100-7ce1-11eb-8cdc-e0d1e7deddb8.png" width="200">
<img src="art/mopub_banner.png" width="200">

Banner Ad
</td>

<td>
<img src="https://user-images.githubusercontent.com/41696219/109938812-7e193880-7ce1-11eb-9629-8002e3f949de.JPG" width="200">
<img src="art/mopub_interstitial.jpg" width="200">


Interstitial Ad
</td>

<td>
<img src="https://user-images.githubusercontent.com/41696219/109938883-8ec9ae80-7ce1-11eb-877b-d48446c9625d.png" width="200">
<img src="art/mopub_rewarded.png" width="200">

Rewarded Ad
</td>
<td>
<img src="https://user-images.githubusercontent.com/41696219/109938979-a5700580-7ce1-11eb-97cc-5bb8480607b8.png" width="200">
<img src="art/mopub_native.png" width="200">

Native Ad
</td>
</tr>
</tr>
</table>

## Huawei
## Huawei Ads
<table>
<tr>
<td>
<img src="https://user-images.githubusercontent.com/41696219/109939215-e36d2980-7ce1-11eb-8ef4-01d9fff6cd83.png" width="200">
<img src="art/huawei_banner.jpg" width="200">

Banner Ad
</td>

<td>
<img src="https://user-images.githubusercontent.com/41696219/109939330-01d32500-7ce2-11eb-9e39-6a9237ca8c54.JPG" width="200">
<img src="art/huawei_interstitial.jpg" width="200">


Interstitial Ad
</td>

<td>
<img src="https://user-images.githubusercontent.com/41696219/109939445-1dd6c680-7ce2-11eb-9e91-fd72b9592d03.JPG" width="200">
<img src="art/huawei_rewarded.jpg" width="200">

Rewarded Ad
</td>

<td>
<img src="art/huawei_native.jpg" width="200">

Native Ad
</td>

</tr>
</tr>
</table>
Expand Down
Binary file added art/huawei_banner.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/huawei_interstitial.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/huawei_native.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/huawei_rewarded.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/mopub_banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/mopub_interstitial.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/mopub_native.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/mopub_rewarded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ import android.content.Context
import android.text.TextUtils
import android.view.View
import com.hmscl.huawei.ads.mediation_adapter_mopub.utils.HuaweiAdsCustomEventDataKeys
import com.huawei.hms.ads.*
import com.hmscl.huawei.ads.mediation_adapter_mopub.utils.HuaweiAdsCustomEventDataKeys.Companion.AD_UNIT_ID_KEY
import com.hmscl.huawei.ads.mediation_adapter_mopub.utils.HuaweiAdsCustomEventDataKeys.Companion.CONTENT_URL_KEY
import com.hmscl.huawei.ads.mediation_adapter_mopub.utils.prepareBuilderViaExtras
import com.huawei.hms.ads.AdListener
import com.huawei.hms.ads.AdParam
import com.huawei.hms.ads.BannerAdSize
import com.huawei.hms.ads.HwAds
import com.huawei.hms.ads.banner.BannerView
import com.mopub.common.LifecycleListener
import com.mopub.common.Preconditions
Expand All @@ -32,12 +38,7 @@ import com.mopub.mobileads.AdData
import com.mopub.mobileads.BaseAd
import com.mopub.mobileads.MoPubErrorCode

class banner: BaseAd() {
val AD_UNIT_ID_KEY = HuaweiAdsCustomEventDataKeys.AD_UNIT_ID_KEY
val CONTENT_URL_KEY = HuaweiAdsCustomEventDataKeys.CONTENT_URL_KEY
val TAG_FOR_CHILD_DIRECTED_KEY = HuaweiAdsCustomEventDataKeys.TAG_FOR_CHILD_DIRECTED_KEY
val TAG_FOR_UNDER_AGE_OF_CONSENT_KEY =
HuaweiAdsCustomEventDataKeys.TAG_FOR_UNDER_AGE_OF_CONSENT_KEY
class banner : BaseAd() {
val ADAPTER_NAME = banner::class.java.simpleName
private lateinit var mHuaweiAdView: BannerView
private var mAdUnitId: String? = null
Expand All @@ -57,10 +58,10 @@ class banner: BaseAd() {
mHuaweiAdView.adId = mAdUnitId

val adSize: BannerAdSize? =
if (adWidth == null || adHeight == null || adWidth!! <= 0 || adHeight!! <= 0) null else BannerAdSize(
adWidth!!,
adHeight!!
)
if (adWidth == null || adHeight == null || adWidth!! <= 0 || adHeight!! <= 0) null else BannerAdSize(
adWidth!!,
adHeight!!
)

if (adSize != null) {
mHuaweiAdView.bannerAdSize = adSize
Expand All @@ -70,55 +71,31 @@ class banner: BaseAd() {
AdapterLogEvent.LOAD_FAILED,
ADAPTER_NAME,
MoPubErrorCode.NETWORK_NO_FILL.intCode,
MoPubErrorCode.NETWORK_NO_FILL
MoPubErrorCode.NETWORK_NO_FILL
)

if (mLoadListener != null) {
mLoadListener.onAdLoadFailed(MoPubErrorCode.NETWORK_NO_FILL)
}
mLoadListener?.onAdLoadFailed(MoPubErrorCode.NETWORK_NO_FILL)
return
}

val builder = AdParam.Builder()
builder.setRequestOrigin("MoPub")

val contentUrl = extras[CONTENT_URL_KEY]

if (!TextUtils.isEmpty(contentUrl)) {
builder.setTargetingContentUrl(contentUrl)
}


val requestConfigurationBuilder = HwAds.getRequestOptions().toBuilder()

val childDirected = extras[TAG_FOR_CHILD_DIRECTED_KEY]
if (childDirected != null) {
if (java.lang.Boolean.parseBoolean(childDirected)) {
requestConfigurationBuilder.setTagForChildProtection(TagForChild.TAG_FOR_CHILD_PROTECTION_TRUE)
} else {
requestConfigurationBuilder.setTagForChildProtection(TagForChild.TAG_FOR_CHILD_PROTECTION_FALSE)
}
} else {
requestConfigurationBuilder.setTagForChildProtection(TagForChild.TAG_FOR_CHILD_PROTECTION_UNSPECIFIED)
}

// Publishers may want to mark their requests to receive treatment for users in the
// European Economic Area (EEA) under the age of consent.
val underAgeOfConsent = extras[TAG_FOR_UNDER_AGE_OF_CONSENT_KEY]
if (underAgeOfConsent != null) {
if (java.lang.Boolean.parseBoolean(underAgeOfConsent)) {
requestConfigurationBuilder.setTagForUnderAgeOfPromise(UnderAge.PROMISE_TRUE)
} else {
requestConfigurationBuilder.setTagForUnderAgeOfPromise(UnderAge.PROMISE_FALSE)
}
} else {
requestConfigurationBuilder.setTagForUnderAgeOfPromise(UnderAge.PROMISE_UNSPECIFIED)
}
/**
* Prepare Child-protection keys
*/
val requestConfigurationBuilder = prepareBuilderViaExtras(extras)
val requestConfiguration = requestConfigurationBuilder.build()
HwAds.setRequestOptions(requestConfiguration)

val adRequest = builder.build()
mHuaweiAdView.loadAd(adRequest)
MoPubLog.log(adNetworkId,AdapterLogEvent.LOAD_ATTEMPTED,ADAPTER_NAME)
MoPubLog.log(adNetworkId, AdapterLogEvent.LOAD_ATTEMPTED, ADAPTER_NAME)
}

override fun getAdView(): View? {
Expand All @@ -142,26 +119,28 @@ class banner: BaseAd() {
override fun checkAndInitializeSdk(
launcherActivity: Activity,
adData: AdData
): kotlin.Boolean {
): Boolean {
return false
}

private inner class AdViewListener: AdListener() {
private inner class AdViewListener : AdListener() {
override fun onAdClosed() {
super.onAdClosed()
}

override fun onAdFailed(loadAdError: Int) {
MoPubLog.log(adNetworkId, AdapterLogEvent.LOAD_FAILED, ADAPTER_NAME,
MoPubLog.log(
adNetworkId, AdapterLogEvent.LOAD_FAILED, ADAPTER_NAME,
getMoPubErrorCode(loadAdError)!!.intCode,
getMoPubErrorCode(loadAdError))
MoPubLog.log(adNetworkId, AdapterLogEvent.CUSTOM, ADAPTER_NAME, "Failed to load Huawei " +
getMoPubErrorCode(loadAdError)
)
MoPubLog.log(
adNetworkId, AdapterLogEvent.CUSTOM, ADAPTER_NAME, "Failed to load Huawei " +
"banners with message: " + loadAdError + ". Caused by: " +
loadAdError)
loadAdError
)

if (mLoadListener != null) {
mLoadListener.onAdLoadFailed(getMoPubErrorCode(loadAdError)!!)
}
mLoadListener?.onAdLoadFailed(getMoPubErrorCode(loadAdError)!!)
}

override fun onAdLeave() {
Expand All @@ -171,41 +150,36 @@ class banner: BaseAd() {
override fun onAdOpened() {
MoPubLog.log(adNetworkId, AdapterLogEvent.CLICKED, ADAPTER_NAME)

if (mInteractionListener != null) {
mInteractionListener.onAdClicked()
}
mInteractionListener?.onAdClicked()
}

override fun onAdLoaded() {
val receivedWidth: Int = mHuaweiAdView.bannerAdSize.width
val receivedHeight: Int = mHuaweiAdView.bannerAdSize.height

if (receivedWidth > adWidth!! || receivedHeight > adHeight!!) {
MoPubLog.log(adNetworkId, AdapterLogEvent.LOAD_FAILED, ADAPTER_NAME,
MoPubLog.log(
adNetworkId, AdapterLogEvent.LOAD_FAILED, ADAPTER_NAME,
MoPubErrorCode.NETWORK_NO_FILL.intCode, MoPubErrorCode.NETWORK_NO_FILL
)
MoPubLog.log(adNetworkId, AdapterLogEvent.CUSTOM, ADAPTER_NAME, "Huawei served an ad but" +
MoPubLog.log(
adNetworkId, AdapterLogEvent.CUSTOM, ADAPTER_NAME, "Huawei served an ad but" +
" it was invalidated because its size of " + receivedWidth + " x " + receivedHeight +
" exceeds the publisher-specified size of " + adWidth + " x " + adHeight)
if (mLoadListener != null) {
mLoadListener.onAdLoadFailed(getMoPubErrorCode(MoPubErrorCode.NETWORK_NO_FILL.intCode)!!)
}
" exceeds the publisher-specified size of " + adWidth + " x " + adHeight
)
mLoadListener?.onAdLoadFailed(getMoPubErrorCode(MoPubErrorCode.NETWORK_NO_FILL.intCode)!!)
} else {
MoPubLog.log(adNetworkId, AdapterLogEvent.LOAD_SUCCESS, ADAPTER_NAME)
MoPubLog.log(adNetworkId, AdapterLogEvent.SHOW_ATTEMPTED, ADAPTER_NAME)
MoPubLog.log(adNetworkId, AdapterLogEvent.SHOW_SUCCESS, ADAPTER_NAME)
if (mLoadListener != null) {
mLoadListener.onAdLoaded()
}
mLoadListener?.onAdLoaded()
}
}

override fun onAdClicked() {
MoPubLog.log(adNetworkId, AdapterLogEvent.CLICKED, ADAPTER_NAME)

if (mInteractionListener != null) {
mInteractionListener.onAdClicked()
}
mInteractionListener?.onAdClicked()
}

override fun onAdImpression() {
Expand Down
Loading

0 comments on commit e0b6a1e

Please sign in to comment.