diff --git a/android/build.gradle b/android/build.gradle index 9e6e140..8172f29 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -9,8 +9,6 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:7.0.4' - // noinspection DifferentKotlinGradleVersion - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.6.10')}" } } @@ -18,7 +16,6 @@ if (isNewArchitectureEnabled()) { apply plugin: "com.facebook.react" } apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' android { compileSdkVersion safeExtGet('compileSdkVersion', 31) diff --git a/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java b/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java new file mode 100644 index 0000000..0c2c699 --- /dev/null +++ b/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java @@ -0,0 +1,232 @@ +package com.adversport.rnaps; + +/* + * Copyright (c) 2022-present Adversport & Contributors + * + * This file is part of react-native-aps. + * + * react-native-aps is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * react-native-aps is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Foobar. If not, see . + */ + +import android.util.SparseArray; +import com.amazon.device.ads.*; +import com.facebook.react.bridge.*; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; +import java.util.List; +import java.util.Map; + +@ReactModule(name = RNAPSAdLoaderModule.MODULE_NAME) +public class RNAPSAdLoaderModule extends ReactContextBaseJavaModule { + + public static final String MODULE_NAME = "RNAPSAdLoaderModule"; + public static final String AD_TYPE_BANNER = "banner"; + public static final String AD_TYPE_INTERSTITIAL = "interstitial"; + public static final String EVENT_SUCCESS = "onSuccess"; + public static final String EVENT_FAILURE = "onFailure"; + + private static final SparseArray adLoaders = new SparseArray<>(); + private final ReactApplicationContext reactContext; + + public RNAPSAdLoaderModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return MODULE_NAME; + } + + private void sendEvent(String eventName, WritableMap params) { + reactContext.getJSModule(RCTDeviceEventEmitter.class).emit(eventName, params); + } + + @ReactMethod + public void addListener(String eventName) { + // Required for event emitter + } + + @ReactMethod + public void removeListeners(double count) { + // Required for event emitter + } + + private class AdCallback implements DTBAdCallback { + private final int loaderId; + private Promise promise; + + public AdCallback(int loaderId, Promise promise) { + this.loaderId = loaderId; + this.promise = promise; + } + + @Override + public void onFailure(AdError adError) { + String code; + AdError.ErrorCode errorCode = adError.getCode(); + if (errorCode == null) { + errorCode = AdError.ErrorCode.NO_ERROR; + } + + switch (errorCode) { + case NO_ERROR: + code = "no_error"; + break; + case NETWORK_ERROR: + code = "network_error"; + break; + case NETWORK_TIMEOUT: + code = "network_timeout"; + break; + case NO_FILL: + code = "no_fill"; + break; + case INTERNAL_ERROR: + code = "internal_error"; + break; + case REQUEST_ERROR: + code = "request_error"; + break; + default: + code = "unknown_error"; + break; + } + + WritableMap userInfoMap = Arguments.createMap(); + userInfoMap.putString("code", code); + userInfoMap.putString("message", adError.getMessage()); + + WritableMap payload = Arguments.createMap(); + payload.putInt("loaderId", loaderId); + payload.putMap("userInfo", userInfoMap); + + sendEvent(EVENT_FAILURE, payload); + if (promise != null) { + // Créer une copie pour promise.reject car userInfoMap est déjà utilisé + WritableMap userInfoCopy = Arguments.createMap(); + userInfoCopy.putString("code", code); + userInfoCopy.putString("message", adError.getMessage()); + promise.reject(code, adError.getMessage(), userInfoCopy); + promise = null; + } + } + + @Override + public void onSuccess(DTBAdResponse response) { + WritableMap responseMap = Arguments.createMap(); + Map> customParams = response.getDefaultDisplayAdsRequestCustomParams(); + + for (Map.Entry> entry : customParams.entrySet()) { + List values = entry.getValue(); + StringBuilder valueBuilder = new StringBuilder(); + for (int i = 0; i < values.size(); i++) { + valueBuilder.append(values.get(i)); + if (i < values.size() - 1) { + valueBuilder.append(","); + } + } + responseMap.putString(entry.getKey(), valueBuilder.toString()); + } + + WritableMap payload = Arguments.createMap(); + payload.putInt("loaderId", loaderId); + payload.putMap("response", responseMap); + + sendEvent(EVENT_SUCCESS, payload); + if (promise != null) { + promise.resolve(responseMap); + promise = null; + } + } + } + + @ReactMethod + public void loadAd(int loaderId, String adType, ReadableMap options, Promise promise) { + stopAutoRefresh(loaderId); + + DTBAdRequest adLoader = new DTBAdRequest(); + + String slotUUID = options.getString("slotUUID"); + if (slotUUID == null) { + promise.reject("invalid_slot_uuid", "slotUUID is required"); + return; + } + + DTBAdSize adSize; + switch (adType) { + case AD_TYPE_BANNER: + String size = options.getString("size"); + if (size == null) { + promise.reject("invalid_size", "size is required for banner ads"); + return; + } + String[] dimensions = size.split("x"); + if (dimensions.length != 2) { + promise.reject("invalid_size", "size must be in format 'WIDTHxHEIGHT'"); + return; + } + try { + int width = Integer.parseInt(dimensions[0]); + int height = Integer.parseInt(dimensions[1]); + adSize = new DTBAdSize(width, height, slotUUID); + } catch (NumberFormatException e) { + promise.reject("invalid_size", "invalid size format: " + size); + return; + } + break; + case AD_TYPE_INTERSTITIAL: + adSize = new DTBAdSize.DTBInterstitialAdSize(slotUUID); + break; + default: + promise.reject("invalid_ad_type", "unsupported ad type: " + adType); + return; + } + + adLoader.setSizes(adSize); + + if (options.hasKey("customTargeting")) { + ReadableMap customTargeting = options.getMap("customTargeting"); + if (customTargeting != null) { + ReadableMapKeySetIterator iterator = customTargeting.keySetIterator(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + String value = customTargeting.getString(key); + if (value != null) { + adLoader.putCustomTarget(key, value); + } + } + } + } + + boolean autoRefresh = options.hasKey("autoRefresh") && options.getBoolean("autoRefresh"); + int refreshInterval = + options.hasKey("refreshInterval") ? options.getInt("refreshInterval") : 60; + + if (autoRefresh) { + adLoader.setAutoRefresh(refreshInterval); + adLoaders.put(loaderId, adLoader); + } + + adLoader.loadAd(new AdCallback(loaderId, promise)); + } + + @ReactMethod + public void stopAutoRefresh(int loaderId) { + DTBAdRequest adLoader = adLoaders.get(loaderId); + if (adLoader != null) { + adLoader.stop(); + adLoaders.remove(loaderId); + } + } +} diff --git a/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.kt b/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.kt deleted file mode 100644 index e4267b2..0000000 --- a/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.kt +++ /dev/null @@ -1,150 +0,0 @@ -package com.adversport.rnaps - -/* - * Copyright (c) 2022-present Adversport & Contributors - * - * This file is part of react-native-aps. - * - * react-native-aps is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, version 3 of the License. - * - * react-native-aps is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Foobar. If not, see . - */ - -import android.util.SparseArray -import com.amazon.device.ads.* -import com.facebook.react.bridge.* -import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter - -@ReactModule(name = RNAPSAdLoaderModule.MODULE_NAME) -class RNAPSAdLoaderModule(private val reactContext: ReactApplicationContext) : - ReactContextBaseJavaModule(reactContext) { - - override fun getName() = MODULE_NAME - - private fun sendEvent(eventName: String, params: WritableMap?) { - reactContext - .getJSModule(RCTDeviceEventEmitter::class.java) - .emit(eventName, params) - } - - @ReactMethod - fun addListener(eventName: String) { - } - - @ReactMethod - fun removeListeners(count: Int) { - } - - private inner class AdCallback(private val loaderId: Int, private var promise: Promise?) : DTBAdCallback { - override fun onFailure(adError: AdError) { - val code = when (adError.code ?: AdError.ErrorCode.NO_ERROR) { - AdError.ErrorCode.NO_ERROR -> "no_error" - AdError.ErrorCode.NETWORK_ERROR -> "network_error" - AdError.ErrorCode.NETWORK_TIMEOUT -> "network_timeout" - AdError.ErrorCode.NO_FILL -> "no_fill" - AdError.ErrorCode.INTERNAL_ERROR -> "internal_error" - AdError.ErrorCode.REQUEST_ERROR -> "request_error" - } - val userInfoMap = Arguments.createMap() - userInfoMap.putString("code", code) - userInfoMap.putString("message", adError.message) - - val payload = Arguments.createMap() - payload.putInt("loaderId", loaderId) - payload.putMap("userInfo", userInfoMap.copy()) - - sendEvent(EVENT_FAILURE, payload) - promise?.reject(code, adError.message, userInfoMap) - promise = null - } - - override fun onSuccess(response: DTBAdResponse) { - val responseMap = Arguments.createMap() - response.defaultDisplayAdsRequestCustomParams.forEach { - responseMap.putString(it.key, it.value.joinToString(postfix = ",")) - } - - val payload = Arguments.createMap() - payload.putInt("loaderId", loaderId) - payload.putMap("response", responseMap.copy()) - - sendEvent(EVENT_SUCCESS, payload) - promise?.resolve(responseMap) - promise = null - } - } - - @ReactMethod - fun loadAd(loaderId: Int, adType: String, options: ReadableMap, promise: Promise) { - stopAutoRefresh(loaderId) - - val adLoader = DTBAdRequest() - - val slotUUID = options.getString("slotUUID")!! - val size = options.getString("size") - val adSize = when (adType) { - AD_TYPE_BANNER -> { - size!!.split("x").let { - DTBAdSize(it[0].toInt(), it[1].toInt(), slotUUID) - } - } - AD_TYPE_INTERSTITIAL -> DTBAdSize.DTBInterstitialAdSize(slotUUID) - else -> return - } - adLoader.setSizes(adSize) - - options.getMap("customTargeting")?.let { - for ((key, value) in it.toHashMap()) { - adLoader.putCustomTarget(key, value as String) - } - } - - val autoRefresh = options.hasKey("autoRefresh").let { - if (it) { - options.getBoolean("autoRefresh") - } else { - false - } - } - - val refreshInterval = options.hasKey("refreshInterval").let { - if (it) { - options.getInt("refreshInterval") - } else { - 60 - } - } - - if (autoRefresh) { - adLoader.setAutoRefresh(refreshInterval) - adLoaders.put(loaderId, adLoader) - } - - adLoader.loadAd(AdCallback(loaderId, promise)) - } - - @ReactMethod - fun stopAutoRefresh(loaderId: Int) { - adLoaders.get(loaderId)?.stop() - adLoaders.remove(loaderId) - } - - companion object { - const val MODULE_NAME = "RNAPSAdLoaderModule" - const val AD_TYPE_BANNER = "banner" - const val AD_TYPE_INTERSTITIAL = "interstitial" - const val EVENT_SUCCESS = "onSuccess" - const val EVENT_FAILURE = "onFailure" - - val adLoaders = SparseArray() - } -} diff --git a/android/src/main/java/com/adversport/rnaps/RNAPSAdsModule.java b/android/src/main/java/com/adversport/rnaps/RNAPSAdsModule.java new file mode 100644 index 0000000..6aa68d7 --- /dev/null +++ b/android/src/main/java/com/adversport/rnaps/RNAPSAdsModule.java @@ -0,0 +1,143 @@ +package com.adversport.rnaps; + +/* + * Copyright (c) 2022-present Adversport & Contributors + * + * This file is part of react-native-aps. + * + * react-native-aps is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * react-native-aps is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Foobar. If not, see . + */ + +import com.amazon.device.ads.AdRegistration; +import com.amazon.device.ads.DTBAdNetwork; +import com.amazon.device.ads.DTBAdNetworkInfo; +import com.amazon.device.ads.MRAIDPolicy; +import com.facebook.react.bridge.*; +import com.facebook.react.module.annotations.ReactModule; +import java.util.ArrayList; + +@ReactModule(name = RNAPSAdsModule.MODULE_NAME) +public class RNAPSAdsModule extends ReactContextBaseJavaModule { + + public static final String MODULE_NAME = "RNAPSAdsModule"; + + public RNAPSAdsModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return MODULE_NAME; + } + + @ReactMethod + public void initialize(String appKey, Promise promise) { + AdRegistration.getInstance(appKey, getReactApplicationContext()); + promise.resolve(null); + } + + @ReactMethod + public void setAdNetworkInfo(ReadableMap adNetworkInfoMap) { + String adNetworkStr = adNetworkInfoMap.getString("adNetwork"); + DTBAdNetwork adNetwork; + + switch (adNetworkStr != null ? adNetworkStr : "OTHER") { + case "GOOGLE_AD_MANAGER": + adNetwork = DTBAdNetwork.GOOGLE_AD_MANAGER; + break; + case "ADMOB": + adNetwork = DTBAdNetwork.ADMOB; + break; + case "AD_GENERATION": + adNetwork = DTBAdNetwork.AD_GENERATION; + break; + case "IRON_SOURCE": + adNetwork = DTBAdNetwork.IRON_SOURCE; + break; + case "MAX": + adNetwork = DTBAdNetwork.MAX; + break; + case "NIMBUS": + adNetwork = DTBAdNetwork.NIMBUS; + break; + default: + adNetwork = DTBAdNetwork.OTHER; + break; + } + + DTBAdNetworkInfo adNetworkInfo = new DTBAdNetworkInfo(adNetwork); + + if (adNetworkInfoMap.hasKey("adNetworkProperties")) { + ReadableMap propertiesMap = adNetworkInfoMap.getMap("adNetworkProperties"); + if (propertiesMap != null) { + ReadableMapKeySetIterator iterator = propertiesMap.keySetIterator(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + String value = propertiesMap.getString(key); + if (value != null) { + adNetworkInfo.setAdNetworkProperties(key, value); + } + } + } + } + + AdRegistration.setAdNetworkInfo(adNetworkInfo); + } + + @ReactMethod + public void setMRAIDSupportedVersions(ReadableArray versions) { + ArrayList versionsList = versions.toArrayList(); + String[] versionsArray = new String[versionsList.size()]; + for (int i = 0; i < versionsList.size(); i++) { + versionsArray[i] = (String) versionsList.get(i); + } + AdRegistration.setMRAIDSupportedVersions(versionsArray); + } + + @ReactMethod + public void setMRAIDPolicy(String policy) { + MRAIDPolicy mraidPolicy; + switch (policy) { + case "NONE": + mraidPolicy = MRAIDPolicy.NONE; + break; + case "DFP": + mraidPolicy = MRAIDPolicy.DFP; + break; + default: + mraidPolicy = MRAIDPolicy.CUSTOM; + break; + } + AdRegistration.setMRAIDPolicy(mraidPolicy); + } + + @ReactMethod + public void setTestMode(boolean enabled) { + AdRegistration.enableTesting(enabled); + } + + @ReactMethod + public void setUseGeoLocation(boolean enabled) { + AdRegistration.useGeoLocation(enabled); + } + + @ReactMethod + public void addCustomAttribute(String key, String value) { + AdRegistration.addCustomAttribute(key, value); + } + + @ReactMethod + public void removeCustomAttribute(String key) { + AdRegistration.removeCustomAttribute(key); + } +} diff --git a/android/src/main/java/com/adversport/rnaps/RNAPSAdsModule.kt b/android/src/main/java/com/adversport/rnaps/RNAPSAdsModule.kt deleted file mode 100644 index 3e70cc5..0000000 --- a/android/src/main/java/com/adversport/rnaps/RNAPSAdsModule.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.adversport.rnaps - -/* - * Copyright (c) 2022-present Adversport & Contributors - * - * This file is part of react-native-aps. - * - * react-native-aps is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, version 3 of the License. - * - * react-native-aps is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Foobar. If not, see . - */ - -import com.amazon.device.ads.AdRegistration -import com.amazon.device.ads.DTBAdNetwork -import com.amazon.device.ads.DTBAdNetworkInfo -import com.amazon.device.ads.MRAIDPolicy -import com.facebook.react.bridge.* -import com.facebook.react.module.annotations.ReactModule - -@ReactModule(name = RNAPSAdsModule.MODULE_NAME) -class RNAPSAdsModule(reactContext: ReactApplicationContext) : - ReactContextBaseJavaModule(reactContext) { - - override fun getName() = MODULE_NAME - - @ReactMethod - fun initialize(appKey: String, promise: Promise) { - AdRegistration.getInstance(appKey, reactApplicationContext) - promise.resolve(null) - } - - @ReactMethod - fun setAdNetworkInfo(adNetworkInfoMap: ReadableMap) { - val adNetwork = when (adNetworkInfoMap.getString("adNetwork")) { - "GOOGLE_AD_MANAGER" -> DTBAdNetwork.GOOGLE_AD_MANAGER - "ADMOB" -> DTBAdNetwork.ADMOB - "AD_GENERATION" -> DTBAdNetwork.AD_GENERATION - "IRON_SOURCE" -> DTBAdNetwork.IRON_SOURCE - "MAX" -> DTBAdNetwork.MAX - "NIMBUS" -> DTBAdNetwork.NIMBUS - else -> DTBAdNetwork.OTHER - } - val adNetworkInfo = DTBAdNetworkInfo(adNetwork) - - adNetworkInfoMap.getMap("adNetworkProperties")?.let { - val properties = it.toHashMap() - - for ((key, value) in properties) { - adNetworkInfo.setAdNetworkProperties(key, value as String) - } - } - - AdRegistration.setAdNetworkInfo(adNetworkInfo) - } - - @ReactMethod - fun setMRAIDSupportedVersions(versions: ReadableArray) { - AdRegistration.setMRAIDSupportedVersions((versions.toArrayList() as List).toTypedArray()) - } - - @ReactMethod - fun setMRAIDPolicy(policy: String) { - AdRegistration.setMRAIDPolicy( - when (policy) { - "NONE" -> MRAIDPolicy.NONE - "DFP" -> MRAIDPolicy.DFP - else -> MRAIDPolicy.CUSTOM - } - ) - } - - @ReactMethod - fun setTestMode(enabled: Boolean) { - AdRegistration.enableTesting(enabled) - } - - @ReactMethod - fun setUseGeoLocation(enabled: Boolean) { - AdRegistration.useGeoLocation(enabled) - } - - @ReactMethod - fun addCustomAttribute(key: String, value: String) { - AdRegistration.addCustomAttribute(key, value) - } - - @ReactMethod - fun removeCustomAttribute(key: String) { - AdRegistration.removeCustomAttribute(key) - } - - companion object { - const val MODULE_NAME = "RNAPSAdsModule" - } -} diff --git a/android/src/main/java/com/adversport/rnaps/RNAPSPackage.kt b/android/src/main/java/com/adversport/rnaps/RNAPSPackage.java similarity index 51% rename from android/src/main/java/com/adversport/rnaps/RNAPSPackage.kt rename to android/src/main/java/com/adversport/rnaps/RNAPSPackage.java index 468cf6e..0d6637b 100644 --- a/android/src/main/java/com/adversport/rnaps/RNAPSPackage.kt +++ b/android/src/main/java/com/adversport/rnaps/RNAPSPackage.java @@ -1,4 +1,4 @@ -package com.adversport.rnaps +package com.adversport.rnaps; /* * Copyright (c) 2022-present Adversport & Contributors @@ -18,18 +18,22 @@ * along with Foobar. If not, see . */ -import com.facebook.react.ReactPackage -import com.facebook.react.bridge.NativeModule -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.uimanager.ViewManager +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; -@Suppress("unused") -class RNAPSPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return listOf(RNAPSAdsModule(reactContext), RNAPSAdLoaderModule(reactContext)) +public class RNAPSPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new RNAPSAdsModule(reactContext), new RNAPSAdLoaderModule(reactContext)); } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return emptyList() + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); } }