@1selfworld/adchain-sdk-react-native 1.0.1
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/LICENSE +20 -0
- package/README.md +211 -0
- package/adchain-sdk-react-native.podspec +25 -0
- package/android/build.gradle +38 -0
- package/android/src/main/java/com/adchain/exposdk/AdchainOfferwallViewManager.kt +288 -0
- package/android/src/main/java/com/adchain/exposdk/AdchainSdkModule.kt +742 -0
- package/android/src/main/java/com/adchain/exposdk/AdchainSdkPackage.kt +14 -0
- package/app.plugin.js +17 -0
- package/ios/AdchainOfferwallViewManager.m +17 -0
- package/ios/AdchainOfferwallViewManager.swift +242 -0
- package/ios/AdchainSdk.m +87 -0
- package/ios/AdchainSdk.swift +792 -0
- package/lib/module/index.js +162 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/index.d.ts +88 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +153 -0
- package/plugin/src/withAdchainAndroid.js +56 -0
- package/plugin/src/withAdchainConfig.js +22 -0
- package/plugin/src/withAdchainIOS.js +60 -0
- package/react-native.config.js +8 -0
- package/src/index.tsx +274 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package com.adchain.exposdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class AdchainSdkPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(rc: ReactApplicationContext): List<NativeModule> =
|
|
10
|
+
listOf(AdchainSdkModule(rc))
|
|
11
|
+
|
|
12
|
+
override fun createViewManagers(rc: ReactApplicationContext): List<ViewManager<*, *>> =
|
|
13
|
+
listOf(AdchainOfferwallViewManager())
|
|
14
|
+
}
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const withAdchainConfig = require('./plugin/src/withAdchainConfig');
|
|
2
|
+
const withAdchainAndroid = require('./plugin/src/withAdchainAndroid');
|
|
3
|
+
const withAdchainIOS = require('./plugin/src/withAdchainIOS');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* v4.1 AdChain Expo SDK Plugin
|
|
7
|
+
* - Config: app.json extra 주입
|
|
8
|
+
* - Android: settings.gradle에 JitPack 추가
|
|
9
|
+
* - iOS: Podfile에 Git Pod 추가 (Swift 5.5)
|
|
10
|
+
*/
|
|
11
|
+
module.exports = (config, props = {}) => {
|
|
12
|
+
config = withAdchainConfig(config, props);
|
|
13
|
+
config = withAdchainAndroid(config);
|
|
14
|
+
config = withAdchainIOS(config);
|
|
15
|
+
|
|
16
|
+
return config;
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#import <React/RCTViewManager.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
@interface RCT_EXTERN_MODULE(AdchainOfferwallViewManager, RCTViewManager)
|
|
5
|
+
|
|
6
|
+
RCT_EXPORT_VIEW_PROPERTY(placementId, NSString)
|
|
7
|
+
RCT_EXPORT_VIEW_PROPERTY(onOfferwallOpened, RCTDirectEventBlock)
|
|
8
|
+
RCT_EXPORT_VIEW_PROPERTY(onOfferwallClosed, RCTDirectEventBlock)
|
|
9
|
+
RCT_EXPORT_VIEW_PROPERTY(onOfferwallError, RCTDirectEventBlock)
|
|
10
|
+
RCT_EXPORT_VIEW_PROPERTY(onRewardEarned, RCTDirectEventBlock)
|
|
11
|
+
RCT_EXPORT_VIEW_PROPERTY(onCustomEvent, RCTDirectEventBlock)
|
|
12
|
+
RCT_EXPORT_VIEW_PROPERTY(onDataRequest, RCTDirectEventBlock)
|
|
13
|
+
|
|
14
|
+
// Export sendDataResponse method for handling data request responses
|
|
15
|
+
RCT_EXTERN_METHOD(sendDataResponse:(nonnull NSNumber *)reactTag requestId:(NSString *)requestId responseData:(NSDictionary *)responseData)
|
|
16
|
+
|
|
17
|
+
@end
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import React
|
|
3
|
+
import AdchainSDK
|
|
4
|
+
|
|
5
|
+
@objc(AdchainOfferwallViewManager)
|
|
6
|
+
class AdchainOfferwallViewManager: RCTViewManager {
|
|
7
|
+
|
|
8
|
+
override func view() -> UIView! {
|
|
9
|
+
let offerwallView = AdchainOfferwallRNView()
|
|
10
|
+
return offerwallView
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override static func requiresMainQueueSetup() -> Bool {
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// NEW: Handle sendDataResponse command from React Native
|
|
18
|
+
@objc func sendDataResponse(_ reactTag: NSNumber, requestId: String, responseData: NSDictionary) {
|
|
19
|
+
DispatchQueue.main.async { [weak self] in
|
|
20
|
+
self?.bridge.uiManager.addUIBlock { (uiManager, viewRegistry) in
|
|
21
|
+
guard let view = viewRegistry?[reactTag] as? AdchainOfferwallRNView else {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
view.sendDataResponse(requestId, responseData: responseData as! [String: Any])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Wrapper view for React Native
|
|
31
|
+
@objc(AdchainOfferwallRNView)
|
|
32
|
+
class AdchainOfferwallRNView: UIView {
|
|
33
|
+
|
|
34
|
+
private var offerwallView: AdchainOfferwallView?
|
|
35
|
+
private var pendingPlacementId: String?
|
|
36
|
+
|
|
37
|
+
@objc var placementId: NSString = "" {
|
|
38
|
+
didSet {
|
|
39
|
+
let placementIdStr = placementId as String
|
|
40
|
+
guard !placementIdStr.isEmpty else { return }
|
|
41
|
+
|
|
42
|
+
pendingPlacementId = placementIdStr
|
|
43
|
+
loadOfferwallIfReady()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@objc var onOfferwallOpened: RCTDirectEventBlock?
|
|
48
|
+
@objc var onOfferwallClosed: RCTDirectEventBlock?
|
|
49
|
+
@objc var onOfferwallError: RCTDirectEventBlock?
|
|
50
|
+
@objc var onRewardEarned: RCTDirectEventBlock?
|
|
51
|
+
@objc var onCustomEvent: RCTDirectEventBlock? // NEW
|
|
52
|
+
@objc var onDataRequest: RCTDirectEventBlock? // NEW
|
|
53
|
+
|
|
54
|
+
// Store pending data responses
|
|
55
|
+
private var pendingDataResponses: [String: [String: Any]] = [:]
|
|
56
|
+
|
|
57
|
+
override init(frame: CGRect) {
|
|
58
|
+
super.init(frame: frame)
|
|
59
|
+
setupOfferwallView()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
required init?(coder: NSCoder) {
|
|
63
|
+
super.init(coder: coder)
|
|
64
|
+
setupOfferwallView()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private func setupOfferwallView() {
|
|
68
|
+
let view = AdchainOfferwallView(frame: bounds)
|
|
69
|
+
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
70
|
+
addSubview(view)
|
|
71
|
+
offerwallView = view
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private func loadOfferwallIfReady() {
|
|
75
|
+
guard let placementId = pendingPlacementId,
|
|
76
|
+
let view = offerwallView else {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
guard let config = AdchainSdk.shared.getConfig(),
|
|
81
|
+
let user = AdchainSdk.shared.getCurrentUser(),
|
|
82
|
+
let offerwallUrl = AdchainSdk.shared.getOfferwallUrl() else {
|
|
83
|
+
if AdchainSdk.shared.getConfig() == nil {
|
|
84
|
+
sendErrorEvent(error: "SDK not initialized")
|
|
85
|
+
} else if AdchainSdk.shared.getCurrentUser() == nil {
|
|
86
|
+
sendErrorEvent(error: "User not logged in")
|
|
87
|
+
} else {
|
|
88
|
+
sendErrorEvent(error: "Offerwall URL not available")
|
|
89
|
+
}
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Set callback for offerwall events
|
|
94
|
+
view.setCallback(RNOfferwallCallback(
|
|
95
|
+
onOpened: { [weak self] in
|
|
96
|
+
self?.sendEvent(name: "onOfferwallOpened", body: [:])
|
|
97
|
+
},
|
|
98
|
+
onClosed: { [weak self] in
|
|
99
|
+
self?.sendEvent(name: "onOfferwallClosed", body: [:])
|
|
100
|
+
},
|
|
101
|
+
onError: { [weak self] error in
|
|
102
|
+
self?.sendEvent(name: "onOfferwallError", body: ["error": error])
|
|
103
|
+
},
|
|
104
|
+
onRewardEarned: { [weak self] amount in
|
|
105
|
+
self?.sendEvent(name: "onRewardEarned", body: ["amount": amount])
|
|
106
|
+
}
|
|
107
|
+
))
|
|
108
|
+
|
|
109
|
+
// NEW: Set event callback for custom events
|
|
110
|
+
view.setEventCallback(RNEventCallback(
|
|
111
|
+
onCustomEvent: { [weak self] (eventType, payload) in
|
|
112
|
+
self?.sendEvent(name: "onCustomEvent", body: [
|
|
113
|
+
"eventType": eventType,
|
|
114
|
+
"payload": payload
|
|
115
|
+
])
|
|
116
|
+
},
|
|
117
|
+
onDataRequest: { [weak self] (requestId, requestType, params) -> [String: Any]? in
|
|
118
|
+
guard let self = self else { return nil }
|
|
119
|
+
|
|
120
|
+
// Send event to React Native
|
|
121
|
+
self.sendEvent(name: "onDataRequest", body: [
|
|
122
|
+
"requestId": requestId,
|
|
123
|
+
"requestType": requestType,
|
|
124
|
+
"params": params
|
|
125
|
+
])
|
|
126
|
+
|
|
127
|
+
// Wait for response from React Native (with timeout)
|
|
128
|
+
let startTime = Date()
|
|
129
|
+
let timeout: TimeInterval = 5.0 // 5 seconds
|
|
130
|
+
|
|
131
|
+
while Date().timeIntervalSince(startTime) < timeout {
|
|
132
|
+
if let response = self.pendingDataResponses.removeValue(forKey: requestId) {
|
|
133
|
+
return response
|
|
134
|
+
}
|
|
135
|
+
Thread.sleep(forTimeInterval: 0.01)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return nil
|
|
139
|
+
}
|
|
140
|
+
))
|
|
141
|
+
|
|
142
|
+
// Load offerwall
|
|
143
|
+
view.loadOfferwall(
|
|
144
|
+
baseUrl: offerwallUrl,
|
|
145
|
+
userId: user.userId,
|
|
146
|
+
appKey: config.appKey,
|
|
147
|
+
placementId: placementId
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
// Clear pending
|
|
151
|
+
pendingPlacementId = nil
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private func sendEvent(name: String, body: [String: Any]) {
|
|
155
|
+
switch name {
|
|
156
|
+
case "onOfferwallOpened":
|
|
157
|
+
onOfferwallOpened?(body)
|
|
158
|
+
case "onOfferwallClosed":
|
|
159
|
+
onOfferwallClosed?(body)
|
|
160
|
+
case "onOfferwallError":
|
|
161
|
+
onOfferwallError?(body)
|
|
162
|
+
case "onRewardEarned":
|
|
163
|
+
onRewardEarned?(body)
|
|
164
|
+
case "onCustomEvent": // NEW
|
|
165
|
+
onCustomEvent?(body)
|
|
166
|
+
case "onDataRequest": // NEW
|
|
167
|
+
onDataRequest?(body)
|
|
168
|
+
default:
|
|
169
|
+
break
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private func sendErrorEvent(error: String) {
|
|
174
|
+
sendEvent(name: "onOfferwallError", body: ["error": error])
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// NEW: Handle data response from React Native
|
|
178
|
+
@objc func sendDataResponse(_ requestId: String, responseData: [String: Any]) {
|
|
179
|
+
pendingDataResponses[requestId] = responseData
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
override func layoutSubviews() {
|
|
183
|
+
super.layoutSubviews()
|
|
184
|
+
offerwallView?.frame = bounds
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Custom callback implementation for React Native
|
|
189
|
+
class RNOfferwallCallback: OfferwallCallback {
|
|
190
|
+
private let onOpenedHandler: () -> Void
|
|
191
|
+
private let onClosedHandler: () -> Void
|
|
192
|
+
private let onErrorHandler: (String) -> Void
|
|
193
|
+
private let onRewardEarnedHandler: (Int) -> Void
|
|
194
|
+
|
|
195
|
+
init(onOpened: @escaping () -> Void,
|
|
196
|
+
onClosed: @escaping () -> Void,
|
|
197
|
+
onError: @escaping (String) -> Void,
|
|
198
|
+
onRewardEarned: @escaping (Int) -> Void) {
|
|
199
|
+
self.onOpenedHandler = onOpened
|
|
200
|
+
self.onClosedHandler = onClosed
|
|
201
|
+
self.onErrorHandler = onError
|
|
202
|
+
self.onRewardEarnedHandler = onRewardEarned
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
func onOpened() {
|
|
206
|
+
onOpenedHandler()
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
func onClosed() {
|
|
210
|
+
onClosedHandler()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
func onError(_ message: String) {
|
|
214
|
+
onErrorHandler(message)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
func onRewardEarned(_ amount: Int) {
|
|
218
|
+
onRewardEarnedHandler(amount)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// NEW: Custom event callback implementation for React Native
|
|
223
|
+
class RNEventCallback: OfferwallEventCallback {
|
|
224
|
+
private let onCustomEventHandler: (String, [String: Any]) -> Void
|
|
225
|
+
private let onDataRequestHandler: (String, String, [String: Any]) -> [String: Any]?
|
|
226
|
+
|
|
227
|
+
init(
|
|
228
|
+
onCustomEvent: @escaping (String, [String: Any]) -> Void,
|
|
229
|
+
onDataRequest: @escaping (String, String, [String: Any]) -> [String: Any]?
|
|
230
|
+
) {
|
|
231
|
+
self.onCustomEventHandler = onCustomEvent
|
|
232
|
+
self.onDataRequestHandler = onDataRequest
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func onCustomEvent(eventType: String, payload: [String: Any]) {
|
|
236
|
+
onCustomEventHandler(eventType, payload)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
func onDataRequest(requestId: String, requestType: String, params: [String: Any]) -> [String: Any]? {
|
|
240
|
+
return onDataRequestHandler(requestId, requestType, params)
|
|
241
|
+
}
|
|
242
|
+
}
|
package/ios/AdchainSdk.m
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
@interface RCT_EXTERN_MODULE(AdchainSdk, RCTEventEmitter)
|
|
5
|
+
|
|
6
|
+
// 1. SDK 초기화
|
|
7
|
+
RCT_EXTERN_METHOD(initialize:(NSString *)appKey
|
|
8
|
+
appSecret:(NSString *)appSecret
|
|
9
|
+
options:(NSDictionary *)options
|
|
10
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
11
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
12
|
+
|
|
13
|
+
// 2. 인증 관련 (4개)
|
|
14
|
+
RCT_EXTERN_METHOD(login:(NSString *)userId
|
|
15
|
+
userInfo:(NSDictionary *)userInfo
|
|
16
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
17
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
18
|
+
|
|
19
|
+
RCT_EXTERN_METHOD(logout:(RCTPromiseResolveBlock)resolver
|
|
20
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
21
|
+
|
|
22
|
+
RCT_EXTERN_METHOD(isLoggedIn:(RCTPromiseResolveBlock)resolver
|
|
23
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
24
|
+
|
|
25
|
+
RCT_EXTERN_METHOD(getCurrentUser:(RCTPromiseResolveBlock)resolver
|
|
26
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
27
|
+
|
|
28
|
+
// 3. Quiz 관련 (2개)
|
|
29
|
+
RCT_EXTERN_METHOD(loadQuizList:(NSString *)unitId
|
|
30
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
31
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
32
|
+
|
|
33
|
+
RCT_EXTERN_METHOD(clickQuiz:(NSString *)unitId
|
|
34
|
+
quizId:(NSString *)quizId
|
|
35
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
36
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
37
|
+
|
|
38
|
+
// 4. Mission 관련 (3개)
|
|
39
|
+
RCT_EXTERN_METHOD(loadMissionList:(NSString *)unitId
|
|
40
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
41
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
42
|
+
|
|
43
|
+
RCT_EXTERN_METHOD(clickMission:(NSString *)unitId
|
|
44
|
+
missionId:(NSString *)missionId
|
|
45
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
46
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
47
|
+
|
|
48
|
+
RCT_EXTERN_METHOD(claimReward:(NSString *)unitId
|
|
49
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
50
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
51
|
+
|
|
52
|
+
// 5. Debug/Utility Methods (3개)
|
|
53
|
+
RCT_EXTERN_METHOD(isInitialized:(RCTPromiseResolveBlock)resolver
|
|
54
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
55
|
+
|
|
56
|
+
RCT_EXTERN_METHOD(getUserId:(RCTPromiseResolveBlock)resolver
|
|
57
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
58
|
+
|
|
59
|
+
RCT_EXTERN_METHOD(getIFA:(RCTPromiseResolveBlock)resolver
|
|
60
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
61
|
+
|
|
62
|
+
// 6. Banner (1개)
|
|
63
|
+
RCT_EXTERN_METHOD(getBannerInfo:(NSString *)placementId
|
|
64
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
65
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
66
|
+
|
|
67
|
+
// 7. Offerwall (3개)
|
|
68
|
+
RCT_EXTERN_METHOD(openOfferwall:(NSString * _Nullable)placementId
|
|
69
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
70
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
71
|
+
|
|
72
|
+
RCT_EXTERN_METHOD(openOfferwallWithUrl:(NSString *)url
|
|
73
|
+
placementId:(NSString * _Nullable)placementId
|
|
74
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
75
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
76
|
+
|
|
77
|
+
RCT_EXTERN_METHOD(openExternalBrowser:(NSString *)url
|
|
78
|
+
placementId:(NSString * _Nullable)placementId
|
|
79
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
80
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
81
|
+
|
|
82
|
+
// 8. Adjoe (1개)
|
|
83
|
+
RCT_EXTERN_METHOD(openAdjoeOfferwall:(NSString * _Nullable)placementId
|
|
84
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
85
|
+
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
86
|
+
|
|
87
|
+
@end
|