Skip to content

Commit

Permalink
Implementation of IronSource Privacy API in the adapter (#1050)
Browse files Browse the repository at this point in the history
* IronSource Privacy APIs implementation

* Updated ironSource GitHub workflow to run unit tests
  • Loading branch information
LTPhantom authored May 9, 2024
1 parent cb17313 commit 890b9b2
Show file tree
Hide file tree
Showing 25 changed files with 697 additions and 44 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/gma_mediation_ironsource.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,56 @@ on:
- main

jobs:
android:
runs-on: macos-latest
if: github.event_name == 'pull_request'
timeout-minutes: 30
steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
with:
fetch-depth: 0
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: "Install Flutter"
run: ./.github/workflows/scripts/install-flutter.sh stable
- name: "Install Tools"
run: ./.github/workflows/scripts/install-tools.sh
- name: "Build Example"
run: ./.github/workflows/scripts/build-example.sh android ./lib/main.dart packages/mediation/gma_mediation_ironsource/example
- name: "Unit Tests"
run: |
cd packages/mediation/gma_mediation_ironsource/example/android
./gradlew :gma_mediation_ironsource:testDebugUnitTest
iOS:
runs-on: macos-latest
timeout-minutes: 40
steps:
- uses: swift-actions/setup-swift@v2
with:
swift-version: "5.7.2"
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
with:
fetch-depth: 0
- name: "Install Flutter"
run: ./.github/workflows/scripts/install-flutter.sh stable
- name: "Install Tools"
run: |
./.github/workflows/scripts/install-tools.sh
- name: "Unit Tests"
run: |
cd packages/mediation/gma_mediation_ironsource/example/ios
flutter clean
flutter pub get
flutter precache --ios
pod install
xcodebuild -configuration Debug -resultBundlePath TestResults VERBOSE_SCRIPT_LOGGING=YES -workspace Runner.xcworkspace -scheme Runner -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.5' test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: iOSTestResults
path: packages/mediation/gma_mediation_ironsource/example/ios/TestResults.xcresult
flutter:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
Expand Down
8 changes: 5 additions & 3 deletions packages/mediation/gma_mediation_ironsource/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## 1.0.0
## ironSource Flutter Mediation Adapter Changelog

#### 1.0.0
* Initial release.
* Verified compatibility with ironSource Android adapter version 7.9.0.0
* Verified compatibility with ironSource iOS adapter version 7.9.1.0.0
* Verified compatibility with ironSource Android adapter version 8.0.0.0
* Verified compatibility with ironSource iOS adapter version 8.0.0.0.0
* Built and tested with the Google Mobile Ads Flutter Plugin version 5.1.0.
2 changes: 1 addition & 1 deletion packages/mediation/gma_mediation_ironsource/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2024 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
#See the License for the specific language governing permissions and
#limitations under the License.

include: package:pedantic/analysis_options.1.11.0.yaml
include: package:lint/package.yaml

analyzer:
exclude:
- '**.g.dart'
27 changes: 20 additions & 7 deletions packages/mediation/gma_mediation_ironsource/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ allprojects {
repositories {
google()
mavenCentral()
maven {
url = uri("https://android-sdk.is.com/")
}
}
}

Expand Down Expand Up @@ -50,20 +53,30 @@ android {
}

dependencies {
implementation 'com.google.ads.mediation:ironsource:7.9.0.0'
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'org.mockito:mockito-core:5.0.0'
implementation 'com.google.ads.mediation:ironsource:8.0.0.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'androidx.test:core:1.5.0'
testImplementation 'androidx.test:core-ktx:1.5.0'
testImplementation 'androidx.test.ext:junit:1.1.5'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib:1.8.20'
testImplementation 'org.mockito:mockito-core:5.5.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.1.0'
testImplementation 'org.robolectric:robolectric:4.10.3'
}

testOptions {
unitTests.all {
useJUnitPlatform()
useJUnit()

testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
unitTests {
includeAndroidResources = true
unitTests.returnDefaultValues = true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
android.useAndroidX=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,31 @@

package io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource

import com.ironsource.mediationsdk.IronSource;
import io.flutter.embedding.engine.plugins.FlutterPlugin

/** GmaMediationIronsourcePlugin. */
class GmaMediationIronsourcePlugin: FlutterPlugin {
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
/** GmaMediationIronsourcePlugin manages IronSourcePrivacyApi and implements the needed methods. */
class GmaMediationIronsourcePlugin: FlutterPlugin, IronSourcePrivacyApi {

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
IronSourcePrivacyApi.setUp(flutterPluginBinding.binaryMessenger, this)
}

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
IronSourcePrivacyApi.setUp(binding.binaryMessenger, null)
}

override fun setConsent(gdprConsent: Boolean) {
IronSource.setConsent(gdprConsent)
}

override fun setDoNotSell(doNotSell: Boolean) {
IronSource.setMetaData(IRONSOURCE_DONOTSELL_KEY, if (doNotSell) TRUE else FALSE)
}

companion object {
const val IRONSOURCE_DONOTSELL_KEY = "do_not_sell"
const val TRUE = "true"
const val FALSE = "false"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Autogenerated from Pigeon (v17.3.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource

import android.util.Log
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MessageCodec
import io.flutter.plugin.common.StandardMessageCodec
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer

private fun wrapResult(result: Any?): List<Any?> {
return listOf(result)
}

private fun wrapError(exception: Throwable): List<Any?> {
if (exception is IronSourcePrivacyError) {
return listOf(
exception.code,
exception.message,
exception.details
)
} else {
return listOf(
exception.javaClass.simpleName,
exception.toString(),
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
)
}
}

/**
* Error class for passing custom error details to Flutter via a thrown PlatformException.
* @property code The error code.
* @property message The error message.
* @property details The error details. Must be a datatype supported by the api codec.
*/
class IronSourcePrivacyError (
val code: String,
override val message: String? = null,
val details: Any? = null
) : Throwable()
/**
* The generated classes set the channels to call the methods in the corresponding kotlin IronSourcePrivacyApi interface and swift IronSourcePrivacyApi protocol from the dart layer.
*
* Generated interface from Pigeon that represents a handler of messages from Flutter.
*/
interface IronSourcePrivacyApi {
fun setConsent(gdprConsent: Boolean)
fun setDoNotSell(doNotSell: Boolean)

companion object {
/** The codec used by IronSourcePrivacyApi. */
val codec: MessageCodec<Any?> by lazy {
StandardMessageCodec()
}
/** Sets up an instance of `IronSourcePrivacyApi` to handle messages through the `binaryMessenger`. */
@Suppress("UNCHECKED_CAST")
fun setUp(binaryMessenger: BinaryMessenger, api: IronSourcePrivacyApi?) {
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.gma_mediation_ironsource.IronSourcePrivacyApi.setConsent", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val gdprConsentArg = args[0] as Boolean
var wrapped: List<Any?>
try {
api.setConsent(gdprConsentArg)
wrapped = listOf<Any?>(null)
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.gma_mediation_ironsource.IronSourcePrivacyApi.setDoNotSell", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val doNotSellArg = args[0] as Boolean
var wrapped: List<Any?>
try {
api.setDoNotSell(doNotSellArg)
wrapped = listOf<Any?>(null)
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,80 @@
package io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource
// Copyright 2024 Google LLC
//
// 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
//
// https://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.

import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlin.test.Test
import org.mockito.Mockito
package io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource

/*
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ironsource.mediationsdk.IronSource
import io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource.GmaMediationIronsourcePlugin.Companion.FALSE
import io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource.GmaMediationIronsourcePlugin.Companion.IRONSOURCE_DONOTSELL_KEY
import io.flutter.plugins.googlemobileads.mediation.gma_mediation_ironsource.GmaMediationIronsourcePlugin.Companion.TRUE
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mockStatic
import org.mockito.kotlin.eq

@RunWith(AndroidJUnit4::class)
internal class GmaMediationIronsourcePluginTest {
@Test
fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
fun setConsent_withTrueValue_invokesIronSourceSetConsent() {
val plugin = GmaMediationIronsourcePlugin()
mockStatic(IronSource::class.java).use { mockedIronSource ->

plugin.setConsent(true)

mockedIronSource.verify {
IronSource.setConsent(eq(true))
}
}
}

@Test
fun setConsent_withFalseValue_invokesIronSourceSetConsent() {
val plugin = GmaMediationIronsourcePlugin()
mockStatic(IronSource::class.java).use { mockedIronSource ->

plugin.setConsent(false)

mockedIronSource.verify {
IronSource.setConsent(eq(false))
}
}
}

@Test
fun setDoNotSell_withTrueValue_invokesIronSourceMetaDataWithCorrectKeyAndValue() {
val plugin = GmaMediationIronsourcePlugin()
mockStatic(IronSource::class.java).use { mockedIronSource ->

plugin.setDoNotSell(true)

mockedIronSource.verify {
IronSource.setMetaData(eq(IRONSOURCE_DONOTSELL_KEY), eq(TRUE))
}
}
}

@Test
fun setDoNotSell_withFalseValue_invokesIronSourceMetaDataWithCorrectKeyAndValue() {
val plugin = GmaMediationIronsourcePlugin()
mockStatic(IronSource::class.java).use { mockedIronSource ->

val call = MethodCall("getPlatformVersion", null)
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
plugin.onMethodCall(call, mockResult)
plugin.setDoNotSell(false)

Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
mockedIronSource.verify {
IronSource.setMetaData(eq(IRONSOURCE_DONOTSELL_KEY), eq(FALSE))
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
Loading

0 comments on commit 890b9b2

Please sign in to comment.