expo-ads 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +8 -8
- package/CHANGELOG.md +11 -11
- package/LICENSE +21 -21
- package/README.md +44 -44
- package/android/build.gradle +33 -33
- package/android/src/main/AndroidManifest.xml +1 -22
- package/android/src/main/java/expo/modules/ads/google/GoogleAdsModule.kt +17 -17
- package/android/src/main/java/expo/modules/ads/meta/MetaAdsInitializer.kt +107 -107
- package/android/src/main/java/expo/modules/ads/meta/MetaAdsModule.kt +93 -40
- package/android/src/main/java/expo/modules/ads/meta/MetaBannerAdSize.kt +26 -0
- package/android/src/main/java/expo/modules/ads/meta/MetaBannerAdView.kt +127 -0
- package/build/google/ExpoAdsGoogleModule.js.map +1 -1
- package/build/google/index.js.map +1 -1
- package/build/meta/ExpoAdsMetaModule.d.ts +34 -0
- package/build/meta/ExpoAdsMetaModule.d.ts.map +1 -1
- package/build/meta/ExpoAdsMetaModule.js.map +1 -1
- package/build/meta/ads/BannerAd.d.ts +16 -0
- package/build/meta/ads/BannerAd.d.ts.map +1 -0
- package/build/meta/ads/BannerAd.js +37 -0
- package/build/meta/ads/BannerAd.js.map +1 -0
- package/build/meta/ads/MetaBannerAdSize.d.ts +24 -0
- package/build/meta/ads/MetaBannerAdSize.d.ts.map +1 -0
- package/build/meta/ads/MetaBannerAdSize.js +25 -0
- package/build/meta/ads/MetaBannerAdSize.js.map +1 -0
- package/build/meta/index.d.ts +4 -0
- package/build/meta/index.d.ts.map +1 -1
- package/build/meta/index.js +2 -0
- package/build/meta/index.js.map +1 -1
- package/build/meta/specs/components/ExpoAdsMetaBannerViewNativeComponent.d.ts +27 -0
- package/build/meta/specs/components/ExpoAdsMetaBannerViewNativeComponent.d.ts.map +1 -0
- package/build/meta/specs/components/ExpoAdsMetaBannerViewNativeComponent.js +5 -0
- package/build/meta/specs/components/ExpoAdsMetaBannerViewNativeComponent.js.map +1 -0
- package/build/meta/types/MetaAdError.d.ts +29 -0
- package/build/meta/types/MetaAdError.d.ts.map +1 -0
- package/build/meta/types/MetaAdError.js +2 -0
- package/build/meta/types/MetaAdError.js.map +1 -0
- package/build/meta/types/MetaBannerAdProps.d.ts +63 -0
- package/build/meta/types/MetaBannerAdProps.d.ts.map +1 -0
- package/build/meta/types/MetaBannerAdProps.js +2 -0
- package/build/meta/types/MetaBannerAdProps.js.map +1 -0
- package/eslint.config.cjs +5 -5
- package/expo-module.config.json +18 -13
- package/ios/Expo-ads.podspec +23 -23
- package/ios/Expo-adsModule.swift +7 -7
- package/package.json +4 -2
- package/src/google/ExpoAdsGoogleModule.ts +6 -6
- package/src/google/index.ts +5 -5
- package/src/meta/ExpoAdsMetaModule.ts +44 -7
- package/src/meta/ads/BannerAd.tsx +63 -0
- package/src/meta/ads/MetaBannerAdSize.tsx +25 -0
- package/src/meta/index.ts +12 -3
- package/src/meta/specs/components/ExpoAdsMetaBannerViewNativeComponent.ts +32 -0
- package/src/meta/types/MetaAdError.ts +31 -0
- package/src/meta/types/MetaBannerAdProps.ts +65 -0
- package/tsconfig.json +28 -28
package/.prettierrc
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
{
|
|
2
|
-
"printWidth": 100,
|
|
3
|
-
"tabWidth": 2,
|
|
4
|
-
"singleQuote": true,
|
|
5
|
-
"bracketSameLine": true,
|
|
6
|
-
"trailingComma": "es5",
|
|
7
|
-
"jsxSingleQuote": false,
|
|
8
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"printWidth": 100,
|
|
3
|
+
"tabWidth": 2,
|
|
4
|
+
"singleQuote": true,
|
|
5
|
+
"bracketSameLine": true,
|
|
6
|
+
"trailingComma": "es5",
|
|
7
|
+
"jsxSingleQuote": false,
|
|
8
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## Unpublished
|
|
4
|
-
|
|
5
|
-
### 🛠 Breaking changes
|
|
6
|
-
|
|
7
|
-
### 🎉 New features
|
|
8
|
-
|
|
9
|
-
### 🐛 Bug fixes
|
|
10
|
-
|
|
11
|
-
### 💡 Others
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unpublished
|
|
4
|
+
|
|
5
|
+
### 🛠 Breaking changes
|
|
6
|
+
|
|
7
|
+
### 🎉 New features
|
|
8
|
+
|
|
9
|
+
### 🐛 Bug fixes
|
|
10
|
+
|
|
11
|
+
### 💡 Others
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
# Expo Ads
|
|
2
|
-
|
|
3
|
-
> 🚧 **This package is currently under construction.**
|
|
4
|
-
|
|
5
|
-
**Expo Ads** is a React Native / Expo native module for integrating mobile advertising networks into Expo applications.
|
|
6
|
-
|
|
7
|
-
## Status
|
|
8
|
-
|
|
9
|
-
**⚠️ Work in Progress**
|
|
10
|
-
|
|
11
|
-
This package is currently under active development. APIs, features, configuration, and implementation details may change without notice.
|
|
12
|
-
|
|
13
|
-
**Not recommended for production use yet.**
|
|
14
|
-
|
|
15
|
-
## Planned Ad Networks
|
|
16
|
-
|
|
17
|
-
- Google Mobile Ads
|
|
18
|
-
- Meta Audience Network
|
|
19
|
-
|
|
20
|
-
<!-- ## Planned Features
|
|
21
|
-
|
|
22
|
-
- Google Mobile Ads initialization
|
|
23
|
-
- Meta Audience Network initialization
|
|
24
|
-
- Banner Ads
|
|
25
|
-
- Interstitial Ads
|
|
26
|
-
- Rewarded Ads
|
|
27
|
-
- Native Ads
|
|
28
|
-
- Expo config plugin support
|
|
29
|
-
- Android support
|
|
30
|
-
- iOS support
|
|
31
|
-
- TypeScript API
|
|
32
|
-
- Expo/EAS Build compatibility
|
|
33
|
-
|
|
34
|
-
## Installation
|
|
35
|
-
|
|
36
|
-
Installation instructions will be provided once the package reaches a stable release.
|
|
37
|
-
|
|
38
|
-
## Development
|
|
39
|
-
|
|
40
|
-
This package is currently being developed and tested locally with Expo and React Native. -->
|
|
41
|
-
|
|
42
|
-
## License
|
|
43
|
-
|
|
44
|
-
MIT
|
|
1
|
+
# Expo Ads
|
|
2
|
+
|
|
3
|
+
> 🚧 **This package is currently under construction.**
|
|
4
|
+
|
|
5
|
+
**Expo Ads** is a React Native / Expo native module for integrating mobile advertising networks into Expo applications.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
**⚠️ Work in Progress**
|
|
10
|
+
|
|
11
|
+
This package is currently under active development. APIs, features, configuration, and implementation details may change without notice.
|
|
12
|
+
|
|
13
|
+
**Not recommended for production use yet.**
|
|
14
|
+
|
|
15
|
+
## Planned Ad Networks
|
|
16
|
+
|
|
17
|
+
- Google Mobile Ads
|
|
18
|
+
- Meta Audience Network
|
|
19
|
+
|
|
20
|
+
<!-- ## Planned Features
|
|
21
|
+
|
|
22
|
+
- Google Mobile Ads initialization
|
|
23
|
+
- Meta Audience Network initialization
|
|
24
|
+
- Banner Ads
|
|
25
|
+
- Interstitial Ads
|
|
26
|
+
- Rewarded Ads
|
|
27
|
+
- Native Ads
|
|
28
|
+
- Expo config plugin support
|
|
29
|
+
- Android support
|
|
30
|
+
- iOS support
|
|
31
|
+
- TypeScript API
|
|
32
|
+
- Expo/EAS Build compatibility
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Installation instructions will be provided once the package reaches a stable release.
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
|
|
40
|
+
This package is currently being developed and tested locally with Expo and React Native. -->
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
package/android/build.gradle
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import groovy.json.JsonSlurper
|
|
2
|
-
|
|
3
|
-
plugins {
|
|
4
|
-
id 'com.android.library'
|
|
5
|
-
id 'expo-module-gradle-plugin'
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
group = 'expo.modules.ads'
|
|
9
|
-
version = '0.1.
|
|
10
|
-
|
|
11
|
-
def packageJson = new JsonSlurper().parseText(file("${projectDir}/../package.json").text)
|
|
12
|
-
|
|
13
|
-
def metaAudienceNetworkVersion = packageJson.sdkVersions.android.metaAudienceNetwork
|
|
14
|
-
def playServicesAdsIdentifierVersion = packageJson.sdkVersions.android.playServicesAdsIdentifier
|
|
15
|
-
def playServicesBasementVersion = packageJson.sdkVersions.android.playServicesBasement
|
|
16
|
-
|
|
17
|
-
android {
|
|
18
|
-
namespace "expo.modules.ads"
|
|
19
|
-
defaultConfig {
|
|
20
|
-
versionCode 1
|
|
21
|
-
versionName "0.1.
|
|
22
|
-
}
|
|
23
|
-
lintOptions {
|
|
24
|
-
abortOnError false
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
dependencies {
|
|
31
|
-
implementation("com.facebook.android:audience-network-sdk:${metaAudienceNetworkVersion}")
|
|
32
|
-
implementation("com.google.android.gms:play-services-ads-identifier:${playServicesAdsIdentifierVersion}")
|
|
33
|
-
implementation("com.google.android.gms:play-services-basement:${playServicesBasementVersion}")
|
|
1
|
+
import groovy.json.JsonSlurper
|
|
2
|
+
|
|
3
|
+
plugins {
|
|
4
|
+
id 'com.android.library'
|
|
5
|
+
id 'expo-module-gradle-plugin'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
group = 'expo.modules.ads'
|
|
9
|
+
version = '0.1.1'
|
|
10
|
+
|
|
11
|
+
def packageJson = new JsonSlurper().parseText(file("${projectDir}/../package.json").text)
|
|
12
|
+
|
|
13
|
+
def metaAudienceNetworkVersion = packageJson.sdkVersions.android.metaAudienceNetwork
|
|
14
|
+
def playServicesAdsIdentifierVersion = packageJson.sdkVersions.android.playServicesAdsIdentifier
|
|
15
|
+
def playServicesBasementVersion = packageJson.sdkVersions.android.playServicesBasement
|
|
16
|
+
|
|
17
|
+
android {
|
|
18
|
+
namespace "expo.modules.ads"
|
|
19
|
+
defaultConfig {
|
|
20
|
+
versionCode 1
|
|
21
|
+
versionName "0.1.1"
|
|
22
|
+
}
|
|
23
|
+
lintOptions {
|
|
24
|
+
abortOnError false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
dependencies {
|
|
31
|
+
implementation("com.facebook.android:audience-network-sdk:${metaAudienceNetworkVersion}")
|
|
32
|
+
implementation("com.google.android.gms:play-services-ads-identifier:${playServicesAdsIdentifierVersion}")
|
|
33
|
+
implementation("com.google.android.gms:play-services-basement:${playServicesBasementVersion}")
|
|
34
34
|
}
|
|
@@ -1,23 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
-
package="expo.modules.meta">
|
|
4
|
-
|
|
5
|
-
<uses-permission android:name="android.permission.INTERNET" />
|
|
6
|
-
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
7
|
-
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
8
|
-
|
|
9
|
-
<application>
|
|
10
|
-
<meta-data
|
|
11
|
-
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
|
12
|
-
android:value="${appJSONGoogleMobileAdsAppID}"/>
|
|
13
|
-
<meta-data
|
|
14
|
-
android:name="com.google.android.gms.ads.DELAY_APP_MEASUREMENT_INIT"
|
|
15
|
-
android:value="${appJSONGoogleMobileAdsDelayAppMeasurementInit}"/>
|
|
16
|
-
<meta-data
|
|
17
|
-
android:name="com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION"
|
|
18
|
-
android:value="${appJSONGoogleMobileAdsOptimizeInitialization}"/>
|
|
19
|
-
<meta-data
|
|
20
|
-
android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING"
|
|
21
|
-
android:value="${appJSONGoogleMobileAdsOptimizeAdLoading}"/>
|
|
22
|
-
</application>
|
|
1
|
+
<manifest>
|
|
23
2
|
</manifest>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
package expo.modules.ads.google
|
|
2
|
-
|
|
3
|
-
import expo.modules.kotlin.modules.Module
|
|
4
|
-
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Placeholder module for Google Mobile Ads support.
|
|
8
|
-
* Will be filled in once the Meta implementation is complete.
|
|
9
|
-
*/
|
|
10
|
-
class GoogleAdsModule : Module() {
|
|
11
|
-
override fun definition() = ModuleDefinition {
|
|
12
|
-
Name("ExpoAdsGoogle") // the name JS uses to find this module (import from "expo-ads/google")
|
|
13
|
-
|
|
14
|
-
// TODO: implement Google Mobile Ads initialization + functions here,
|
|
15
|
-
// mirroring the structure of MetaAdsModule / MetaAdsInitializer.
|
|
16
|
-
}
|
|
17
|
-
}
|
|
1
|
+
package expo.modules.ads.google
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.modules.Module
|
|
4
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Placeholder module for Google Mobile Ads support.
|
|
8
|
+
* Will be filled in once the Meta implementation is complete.
|
|
9
|
+
*/
|
|
10
|
+
class GoogleAdsModule : Module() {
|
|
11
|
+
override fun definition() = ModuleDefinition {
|
|
12
|
+
Name("ExpoAdsGoogle") // the name JS uses to find this module (import from "expo-ads/google")
|
|
13
|
+
|
|
14
|
+
// TODO: implement Google Mobile Ads initialization + functions here,
|
|
15
|
+
// mirroring the structure of MetaAdsModule / MetaAdsInitializer.
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
package expo.modules.ads.meta
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.content.pm.ApplicationInfo
|
|
5
|
-
import android.os.Handler
|
|
6
|
-
import android.os.Looper
|
|
7
|
-
import android.util.Log
|
|
8
|
-
import com.facebook.ads.AdSettings
|
|
9
|
-
import com.facebook.ads.AudienceNetworkAds
|
|
10
|
-
|
|
11
|
-
object MetaAdsInitializer : AudienceNetworkAds.InitListener {
|
|
12
|
-
|
|
13
|
-
const val TAG = "ExpoAdsMeta"
|
|
14
|
-
|
|
15
|
-
private enum class State { IDLE, INITIALIZING, READY, FAILED }
|
|
16
|
-
|
|
17
|
-
private val lock = Any()
|
|
18
|
-
private var state = State.IDLE
|
|
19
|
-
private var lastMessage = ""
|
|
20
|
-
private val pending = mutableListOf<(Boolean, String) -> Unit>()
|
|
21
|
-
|
|
22
|
-
fun isReady(): Boolean = synchronized(lock) { state == State.READY }
|
|
23
|
-
|
|
24
|
-
fun whenReady(context: Context, callback: (success: Boolean, message: String) -> Unit) {
|
|
25
|
-
val appContext = context.applicationContext
|
|
26
|
-
var startInit = false
|
|
27
|
-
var immediate: Pair<Boolean, String>? = null
|
|
28
|
-
|
|
29
|
-
synchronized(lock) {
|
|
30
|
-
when (state) {
|
|
31
|
-
State.READY -> {
|
|
32
|
-
Log.d(TAG, "[Init] Already initialized, running callback immediately")
|
|
33
|
-
immediate = true to lastMessage
|
|
34
|
-
}
|
|
35
|
-
State.INITIALIZING -> {
|
|
36
|
-
pending.add(callback)
|
|
37
|
-
Log.d(TAG, "[Init] Initialization in progress, callback queued (${pending.size} waiting)")
|
|
38
|
-
}
|
|
39
|
-
State.IDLE -> {
|
|
40
|
-
Log.i(TAG, "[Init] First-time initialization requested")
|
|
41
|
-
state = State.INITIALIZING
|
|
42
|
-
pending.add(callback)
|
|
43
|
-
startInit = true
|
|
44
|
-
}
|
|
45
|
-
State.FAILED -> {
|
|
46
|
-
Log.w(TAG, "[Init] Previous initialization failed ($lastMessage), retrying")
|
|
47
|
-
state = State.INITIALIZING
|
|
48
|
-
pending.add(callback)
|
|
49
|
-
startInit = true
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
immediate?.let { callback(it.first, it.second); return }
|
|
55
|
-
|
|
56
|
-
if (startInit) {
|
|
57
|
-
Handler(Looper.getMainLooper()).post { doInitialize(appContext) }
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private fun doInitialize(context: Context) {
|
|
62
|
-
try {
|
|
63
|
-
if (AudienceNetworkAds.isInitialized(context)) {
|
|
64
|
-
Log.i(TAG, "[Init] SDK reports it is already initialized (skipping initialize())")
|
|
65
|
-
finish(true, "Already initialized")
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
val isDebuggable = (context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
|
|
70
|
-
if (isDebuggable) {
|
|
71
|
-
AdSettings.turnOnSDKDebugger(context)
|
|
72
|
-
Log.d(TAG, "[Debug] SDK debugger ENABLED (debuggable build)")
|
|
73
|
-
} else {
|
|
74
|
-
Log.d(TAG, "[Debug] SDK debugger NOT set (release build)")
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
Log.i(TAG, "[Init] Calling AudienceNetworkAds.initialize()")
|
|
78
|
-
AudienceNetworkAds
|
|
79
|
-
.buildInitSettings(context)
|
|
80
|
-
.withInitListener(this)
|
|
81
|
-
.initialize()
|
|
82
|
-
} catch (e: Exception) {
|
|
83
|
-
Log.e(TAG, "[Init] initialize() threw an exception: ${e.message}", e)
|
|
84
|
-
finish(false, e.message ?: "Unknown exception during initialize")
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
override fun onInitialized(result: AudienceNetworkAds.InitResult) {
|
|
89
|
-
if (result.isSuccess) {
|
|
90
|
-
Log.i(TAG, "[Init] SUCCESS: ${result.message}")
|
|
91
|
-
} else {
|
|
92
|
-
Log.e(TAG, "[Init] FAILED: ${result.message}")
|
|
93
|
-
}
|
|
94
|
-
finish(result.isSuccess, result.message)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private fun finish(success: Boolean, message: String) {
|
|
98
|
-
val callbacks: List<(Boolean, String) -> Unit>
|
|
99
|
-
synchronized(lock) {
|
|
100
|
-
state = if (success) State.READY else State.FAILED
|
|
101
|
-
lastMessage = message
|
|
102
|
-
callbacks = pending.toList()
|
|
103
|
-
pending.clear()
|
|
104
|
-
}
|
|
105
|
-
Log.d(TAG, "[Init] Notifying ${callbacks.size} waiting callback(s), success=$success")
|
|
106
|
-
callbacks.forEach { it(success, message) }
|
|
107
|
-
}
|
|
1
|
+
package expo.modules.ads.meta
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.pm.ApplicationInfo
|
|
5
|
+
import android.os.Handler
|
|
6
|
+
import android.os.Looper
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import com.facebook.ads.AdSettings
|
|
9
|
+
import com.facebook.ads.AudienceNetworkAds
|
|
10
|
+
|
|
11
|
+
object MetaAdsInitializer : AudienceNetworkAds.InitListener {
|
|
12
|
+
|
|
13
|
+
const val TAG = "ExpoAdsMeta"
|
|
14
|
+
|
|
15
|
+
private enum class State { IDLE, INITIALIZING, READY, FAILED }
|
|
16
|
+
|
|
17
|
+
private val lock = Any()
|
|
18
|
+
private var state = State.IDLE
|
|
19
|
+
private var lastMessage = ""
|
|
20
|
+
private val pending = mutableListOf<(Boolean, String) -> Unit>()
|
|
21
|
+
|
|
22
|
+
fun isReady(): Boolean = synchronized(lock) { state == State.READY }
|
|
23
|
+
|
|
24
|
+
fun whenReady(context: Context, callback: (success: Boolean, message: String) -> Unit) {
|
|
25
|
+
val appContext = context.applicationContext
|
|
26
|
+
var startInit = false
|
|
27
|
+
var immediate: Pair<Boolean, String>? = null
|
|
28
|
+
|
|
29
|
+
synchronized(lock) {
|
|
30
|
+
when (state) {
|
|
31
|
+
State.READY -> {
|
|
32
|
+
Log.d(TAG, "[Init] Already initialized, running callback immediately")
|
|
33
|
+
immediate = true to lastMessage
|
|
34
|
+
}
|
|
35
|
+
State.INITIALIZING -> {
|
|
36
|
+
pending.add(callback)
|
|
37
|
+
Log.d(TAG, "[Init] Initialization in progress, callback queued (${pending.size} waiting)")
|
|
38
|
+
}
|
|
39
|
+
State.IDLE -> {
|
|
40
|
+
Log.i(TAG, "[Init] First-time initialization requested")
|
|
41
|
+
state = State.INITIALIZING
|
|
42
|
+
pending.add(callback)
|
|
43
|
+
startInit = true
|
|
44
|
+
}
|
|
45
|
+
State.FAILED -> {
|
|
46
|
+
Log.w(TAG, "[Init] Previous initialization failed ($lastMessage), retrying")
|
|
47
|
+
state = State.INITIALIZING
|
|
48
|
+
pending.add(callback)
|
|
49
|
+
startInit = true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
immediate?.let { callback(it.first, it.second); return }
|
|
55
|
+
|
|
56
|
+
if (startInit) {
|
|
57
|
+
Handler(Looper.getMainLooper()).post { doInitialize(appContext) }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun doInitialize(context: Context) {
|
|
62
|
+
try {
|
|
63
|
+
if (AudienceNetworkAds.isInitialized(context)) {
|
|
64
|
+
Log.i(TAG, "[Init] SDK reports it is already initialized (skipping initialize())")
|
|
65
|
+
finish(true, "Already initialized")
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
val isDebuggable = (context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
|
|
70
|
+
if (isDebuggable) {
|
|
71
|
+
AdSettings.turnOnSDKDebugger(context)
|
|
72
|
+
Log.d(TAG, "[Debug] SDK debugger ENABLED (debuggable build)")
|
|
73
|
+
} else {
|
|
74
|
+
Log.d(TAG, "[Debug] SDK debugger NOT set (release build)")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Log.i(TAG, "[Init] Calling AudienceNetworkAds.initialize()")
|
|
78
|
+
AudienceNetworkAds
|
|
79
|
+
.buildInitSettings(context)
|
|
80
|
+
.withInitListener(this)
|
|
81
|
+
.initialize()
|
|
82
|
+
} catch (e: Exception) {
|
|
83
|
+
Log.e(TAG, "[Init] initialize() threw an exception: ${e.message}", e)
|
|
84
|
+
finish(false, e.message ?: "Unknown exception during initialize")
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
override fun onInitialized(result: AudienceNetworkAds.InitResult) {
|
|
89
|
+
if (result.isSuccess) {
|
|
90
|
+
Log.i(TAG, "[Init] SUCCESS: ${result.message}")
|
|
91
|
+
} else {
|
|
92
|
+
Log.e(TAG, "[Init] FAILED: ${result.message}")
|
|
93
|
+
}
|
|
94
|
+
finish(result.isSuccess, result.message)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun finish(success: Boolean, message: String) {
|
|
98
|
+
val callbacks: List<(Boolean, String) -> Unit>
|
|
99
|
+
synchronized(lock) {
|
|
100
|
+
state = if (success) State.READY else State.FAILED
|
|
101
|
+
lastMessage = message
|
|
102
|
+
callbacks = pending.toList()
|
|
103
|
+
pending.clear()
|
|
104
|
+
}
|
|
105
|
+
Log.d(TAG, "[Init] Notifying ${callbacks.size} waiting callback(s), success=$success")
|
|
106
|
+
callbacks.forEach { it(success, message) }
|
|
107
|
+
}
|
|
108
108
|
}
|
|
@@ -1,40 +1,93 @@
|
|
|
1
|
-
package expo.modules.ads.meta
|
|
2
|
-
|
|
3
|
-
import android.util.Log
|
|
4
|
-
import
|
|
5
|
-
import expo.modules.kotlin.
|
|
6
|
-
import expo.modules.kotlin.modules.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
MetaAdsInitializer.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
MetaAdsInitializer.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
package expo.modules.ads.meta
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.facebook.ads.AdSettings
|
|
5
|
+
import expo.modules.kotlin.Promise
|
|
6
|
+
import expo.modules.kotlin.modules.Module
|
|
7
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
8
|
+
|
|
9
|
+
class MetaAdsModule : Module() {
|
|
10
|
+
override fun definition() = ModuleDefinition {
|
|
11
|
+
Name("ExpoAdsMeta") // the name JS uses to find this module (import from "expo-ads/meta")
|
|
12
|
+
|
|
13
|
+
// Runs automatically when the module loads (warm-up)
|
|
14
|
+
OnCreate {
|
|
15
|
+
val ctx = appContext.reactContext
|
|
16
|
+
if (ctx == null) {
|
|
17
|
+
Log.w(MetaAdsInitializer.TAG, "[Module] OnCreate: React context is null, skipping warm-up")
|
|
18
|
+
} else {
|
|
19
|
+
Log.d(MetaAdsInitializer.TAG, "[Module] OnCreate: starting SDK warm-up")
|
|
20
|
+
MetaAdsInitializer.whenReady(ctx) { _, _ -> }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Lets JS call: await ExpoAdsMeta.initialize()
|
|
25
|
+
AsyncFunction("initialize") { promise: Promise ->
|
|
26
|
+
val ctx = appContext.reactContext
|
|
27
|
+
if (ctx == null) {
|
|
28
|
+
Log.e(MetaAdsInitializer.TAG, "[Module] initialize() called from JS but React context is null")
|
|
29
|
+
promise.reject("ERR_NO_CONTEXT", "React context not available", null)
|
|
30
|
+
return@AsyncFunction
|
|
31
|
+
}
|
|
32
|
+
Log.d(MetaAdsInitializer.TAG, "[Module] initialize() called from JS")
|
|
33
|
+
MetaAdsInitializer.whenReady(ctx) { ok, msg ->
|
|
34
|
+
if (ok) promise.resolve(msg) else promise.reject("ERR_META_INIT", msg, null)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Lets JS call: await ExpoAdsMeta.setTestMode(true)
|
|
39
|
+
//
|
|
40
|
+
// This is a plain static AdSettings toggle with no I/O, so it's a synchronous Function
|
|
41
|
+
// rather than an AsyncFunction — but it's still safe (and expected) to `await` it from
|
|
42
|
+
// JS, since every native function on this module returns a Promise from the JS side
|
|
43
|
+
// regardless of whether it's sync or async natively.
|
|
44
|
+
//
|
|
45
|
+
// Deliberately NOT gated on MetaAdsInitializer.isReady(): Meta's own docs call this
|
|
46
|
+
// (and addTestDevices) *before* the SDK finishes async initialization — test mode and
|
|
47
|
+
// test devices must be registered before the first loadAd() call, not after init.
|
|
48
|
+
Function("setTestMode") { enabled: Boolean ->
|
|
49
|
+
Log.d(MetaAdsInitializer.TAG, "[Module] setTestMode($enabled)")
|
|
50
|
+
AdSettings.setTestMode(enabled)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Lets JS call: await ExpoAdsMeta.addTestDevices(["HASHED_ID_1", "HASHED_ID_2"])
|
|
54
|
+
//
|
|
55
|
+
// Accepts a list so a single call can register every test device hash at once; each
|
|
56
|
+
// hash is normally copied from Logcat the first time a real ad request is made on that
|
|
57
|
+
// device (see MetaAdsInitializer's warm-up call in OnCreate above, or any loadAd()).
|
|
58
|
+
Function("addTestDevices") { deviceHashes: List<String> ->
|
|
59
|
+
Log.d(MetaAdsInitializer.TAG, "[Module] addTestDevices(${deviceHashes.size} device(s))")
|
|
60
|
+
AdSettings.addTestDevices(deviceHashes)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Lets JS call: await ExpoAdsMeta.clearTestDevices()
|
|
64
|
+
//
|
|
65
|
+
// Mirrors Meta's documented "before shipping" cleanup step
|
|
66
|
+
// (AdSettings.setTestMode(false); AdSettings.clearTestDevices();). Exposed separately
|
|
67
|
+
// from setTestMode(false) so callers can clear registered device hashes independently.
|
|
68
|
+
Function("clearTestDevices") {
|
|
69
|
+
Log.d(MetaAdsInitializer.TAG, "[Module] clearTestDevices()")
|
|
70
|
+
AdSettings.clearTestDevices()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Banner ad native view, exposed to JS as <ExpoAdsMetaBannerView>.
|
|
74
|
+
View(MetaBannerAdView::class) {
|
|
75
|
+
Events("onAdLoaded", "onAdFailedToLoad", "onAdClicked", "onLoggingImpression")
|
|
76
|
+
|
|
77
|
+
Prop("unitId") { view: MetaBannerAdView, value: String? ->
|
|
78
|
+
view.setUnitId(value)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Prop("size") { view: MetaBannerAdView, value: MetaBannerAdSize ->
|
|
82
|
+
view.setSize(value)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Fires after unitId/size are applied for this commit, mirroring the
|
|
86
|
+
// onAfterUpdateTransaction "props changed -> (re)request" pattern used by the reference
|
|
87
|
+
// Google Mobile Ads ViewManager, but expressed as an Expo Modules view lifecycle hook.
|
|
88
|
+
OnViewDidUpdateProps { view: MetaBannerAdView ->
|
|
89
|
+
view.requestAd()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|