ReactNative GreenpOfferwall forExtends SDK 가이드 - rnd-adforus/GreenpSDK_Android GitHub Wiki
ReactNative GreenpOfferwall SDK forExtends 가이드는 Native로 개발되어 있는 GreenpOfferwall SDK forExtends를 ReactNative 환경에서 적용 가능하도록 구성된 샘플 코드 가이드 입니다. 다음의 구현 사항을 준수한 샘플 앱 다운로드 경로로 샘플 코드 적용을 확인 할 수 있습니다. ReactNative - GreenpOfferwall SDK forExtends Sample
- ReactNative Greenp Offerwall v3 For Extend
-
platform 별 초기 세팅
1-1 AOS
(1) build.gradle 설정
(2) AndroidManifest.xml 설정
(3) Proguard 설정
(4) Native Interface 호출 필수 설정
1-2 iOS
(1) Installation 설정
(2) Info.plist 설정
(3) Native Interface 호출 필수 설정
- SDK 초기화
- SDK 사용법
- 콜백 URL 파라미터 설정
Greenp Offerwall Android v3 For Extend은 그린피 오퍼월 광고와 구글 광고(배너, 전면, 리워드, 네이티브)를 모두 지원 받을 수 있는 통합 SDK 서비스입니다.
그린피 오퍼월 내에서도 다음과 같이 구글 광고가 지원됩니다.
구글 광고 송출을 위한 운영 프로세스를 선 진행해 주시길 바랍니다.
GreenPOfferwall + Google 통합 MCM 가이드
최소 지원 Android 버전은 ReactNative 프로젝트 > android > build.gradle 을 열고 의존성 Maven url을 설정합니다.
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven{
url 'https://nexus.adforus.com/repository/greenp/'
}
maven{
url 'https://artifact.bytedance.com/repository/pangle/'
}
}
}
ReactNative 프로젝트 > android > app > build.gradle 을 열고 의존성 목록을 추가합니다.
dependencies {
...
// 가이드 문서 내 최신버전 참고
implementation 'com.adforus.sdk:greenp_v3:3.4.2.0-UAD'
}
ReactNative 프로젝트 > android > app > src > main > AndroidManifest.xml 파일에 권한 설정을 추가합니다. 개인 식별과 리워드 적립을 위해서는 아래의 권한이 필요합니다. 권한 설정이 되지 않는 경우 SDK를 사용할 수 없습니다.
<uses-permission android:name=“android.permission.ACCESS_NETWORK_STATE”/>
<uses-permission android:name=“com.google.android.gms.permission.AD_ID”/>
<!-- CS 첨부파일 등록을 위해 외부 파일 접근권한이 필요합니다. api level에 따라 선택해서 선언해주세요. -->
<!-- targetSdk 32 이하 -->
<uses-permission android:name=“android.permission.READ_EXTERNAL_STORAGE”/>
<!-- targetSdk 33 이상 -->
<uses-permission android:name=“android.permission.READ_MEDIA_IMAGES”/>
[HTTP 트래픽 허용 관련]
그린피 SDK 에서는 HTTPS 를 사용하고 있지 않습니다. 따라서 SDK의 AndroidManifest.xml 을 통해 아래의 내용을 포함하고 있습니다.
(그린피에서는 많은 광고사를 실시간으로 연동하고 있어 여러 도메인이 추가/삭제 될 수 있습니다. 가급적 모든 HTTP 트래픽의 허용을 권장드립니다.)
<application
...
android:usesCleartextTraffic="true">
...
<application/>
앱의 보안을 위해 HTTP 프로토콜을 허용하지 않고자 하시는 경우 AndroidManifest.xml에 usesCleartextTraffic 을 false 로 변경 후 ReactNative 프로젝트 Root > android > app > src > main > res > xml 위치에 network_security_config.xml을 생성하고 아래의 도메인을 예외사항으로 추가해주세요. (허용이 필요한 도메인의 목록은 예고없이 추가/삭제 될 수 있습니다.) [network_security_config.xml]
<domain includeSubdomains="true">greenp.kr</domain>
<domain includeSubdomains="true">decaffeine.net</domain>
<domain includeSubdomains="true">adboost.co.kr</domain>
[Application ID 설정] 구글 광고 호출을 위한 Application ID을 application 태그 내부에 작성하여주세요. (앱별 Application ID를 Adforus 운영팀에 문의해주세요.)
<application>
...
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="Your Admob Application ID"/>
</application>
ReactNative 프로젝트 > android > app > proguard-rules.pro 에 다음을 추가하여 난독화 시 구현에 필요한 인터페이스의 난독화가 되지 않도록 설정해주세요.
-keep class com.adforus.sdk.greenp.v3.** { *; }
-dontwarn com.adforus.sdk.greenp.v3.**
- ReactContextBaseJavaModule 구현 클래스 생성 ( ReactNative 프로젝트 Root > android > app > src > main > 패키지경로 )
- ReactPackage 구현 클래스 생성 ( ReactNative 프로젝트 Root > android > app > src > main > 패키지경로 )
- MainApplication에 ReactPackage 구현 클래스 모듈 수동 등록 ( ReactNative 프로젝트 Root > android > app > src > main > 패키지경로 > MainApplication )
[ReactContextBaseJavaModule 구현 클래스 생성 및 구현] GreenpOfferwall SDK Android의 Native 인터페이스를 호출하기 위해 ReactContextBaseJavaModule을 구현한 클래스를 작성합니다.
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.adforus.sdk.greenp.v3.GreenpReward;
import com.adforus.sdk.greenp.v3.OfferwallBuilder;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class GreenpModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
private final Context context;
private OfferwallBuilder builder = null;
private Callback callback = null;
public GreenpModule(@Nullable ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.context = reactContext.getApplicationContext();
}
@NonNull
@Override
public String getName() {
return "GreenpModule";
}
@ReactMethod
public void initialized(String appCode, String userId, Callback callback){
if(this.callback == null) {
this.callback = callback;
}
if(context != null) {
if(reactContext.getCurrentActivity() == null) {
GreenpReward.init(context, appCode, userId, new GreenpReward.OnGreenpRewardListener() {
@Override
public void onResult(boolean result, String msg) {
sendResult(result, msg, appCode);
}
});
}else {
GreenpReward.init(reactContext.getCurrentActivity(), appCode, userId, new GreenpReward.OnGreenpRewardListener() {
@Override
public void onResult(boolean result, String msg) {
sendResult(result, msg, appCode);
}
});
}
}
}
private void sendResult(boolean result, String msg, String appCode) {
if(this.callback != null ) {
if(result) {
builder = GreenpReward.getOfferwallBuilder();
if(builder != null) {
builder.setAppUniqKey(appCode);
}
}
this.callback.invoke(result, msg);
}
}
@ReactMethod
public void show(){
if(builder != null && reactContext.getCurrentActivity() != null){
builder.showOfferwall(reactContext.getCurrentActivity());
}
}
}
[ReactPackage 구현 클래스 생성 및 구현] ReactNative에서 생성한 모듈을 인식할 수 있도록 다음과 같이 ReactPackage를 구현합니다.
import androidx.annotation.NonNull;
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.ArrayList;
import java.util.Collections;
import java.util.List;
public class GreenpPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactApplicationContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new GreenpModule(reactApplicationContext));
return modules;
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
return Collections.emptyList();
}
}
[ReactPackage 구현 클래스 모듈 수동 등록] 사용자 정의 Module을 ReactNative용으로 구현한 ReactPackage 구현 클래스를 다음과 같이 DefaultReactNativeHost 클래스의 ReactPackage 목록으로 추가 합니다.
import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(GreenpPackage()) //Module 수동 등록
}
... 생략 ...
}
... 생략 ...
}
ReactNative 프로젝트 Root > ios > Podfile 을 열고 의존성 설정을 추가하여 주십시오.
- GreepPOfferwall SDK의 최소 iOS 지원 버전은 14.0 입니다.
- 타겟 모듈 내의 설정에서 use_react_native! 선언 부 상단에 use_framework! 선언과 함께 GreenpOfferwall SDK pod 의존성을 작성 합니다.
- 라이브러리의 표준화된 호환성 보장을 위해 post_install 내에 BUILD_LIBRARY_FOR_DISTRIBUTION 설정을 추가합니다.
수정된 Podfile을 저장하고, ios 경로에서 터미널 명령으로 pod update 와 pod install 명령으로 프로젝트 내에 의존성을 적용합니다.
platform :ios, '14.0'
''' 중략 '''
target 'YourProject' do
config = use_native_modules!
use_frameworks!
pod 'GreenPOfferWallExs', '3.4.0.0'
use_react_native!(
:path => config[:reactNativePath],
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
''' 중략 '''
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
# https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
react_native_post_install(
installer,
config[:reactNativePath],
:mac_catalyst_enabled => false,
# :ccache_enabled => true
)
end
end
광고 추적 권한 허용 여부에 사용 되는 문구 설정 및 오퍼월 광고 지원을 위한 api 통신 설정이 다음과 같이 필요합니다. 다음의 설정이 올바르지 않을 시 오퍼월 리워드 지급이 원활하지 않을 수 있습니다. ReactNative 프로젝트 > ios > YourProject.xcworkspace을 xcode로 열고 Info.plist에 다음과 같이 추가 설정합니다.
[광고 추적 권한에 따른 문구 설정]
[http 통신 예외처리]
[Application ID 설정 및 광고 최적화 설정]
GADApplicationIdentifier키 값에 Application Id를 입력하세요. (앱별 Application ID를 Adforus 운영팀에 문의해주세요.)
또는
<key>GADApplicationIdentifier</key>
<string>Your Application ID</string>
광고 최적화를 위해 광고 추적 예외 설정에 필요한 값을 추가합니다. 아래 스니펫을 Info.plist에 포함하여 주세요.
작성예시
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4fzdc2evr5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4pfyvq9l8r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2fnua5tdw4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ydx93a7ass.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>5a6flpkh64.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>p78axxw29g.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v72qych5uu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ludvb6z3bs.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cp8zw746q7.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3sh42y64q3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>c6k4g5qg8m.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>s39g8k73mm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qy4746246.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f38h382jlk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>hs6bdukanm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v4nxqhlyqp.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>wzmmz9fp6w.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>yclnxrl5pm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>t38b2kh725.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7ug5zh24hu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>gta9lk7p23.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>vutu7akeur.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>y5ghdn5j9k.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n6fk4nfna4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v9wttpbfk9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n38lu8286q.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>47vhws6wlr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>kbd757ywx3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9t245vhmpl.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>eh6m2bh4zr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>a2p9lx4jpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>22mmun2rn5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4468km3ulz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2u9pt9hc89.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8s468mfl3y.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>klf5c3l5u5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ppxm28t8ap.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ecpz2srf59.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>uw77j35x4d.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>pwa73g5rt2.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>mlmmfzh3r3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>578prtvx9j.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4dzt52r2t5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>e5fvkxwrpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8c4e2ghe7u.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>zq492l623r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3rd42ekr43.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qcr597p9d.skadnetwork</string>
</dict>
</array>
- RCTBridgeModule swift 클래스 구현 ( ReactNative 프로젝트 Root > ios > 프로젝트 디렉토리 )
- RCTBridgeModule swift 클래스를 Objective-C로 연결하는 implementation File (.m) 구현 ( ios > 프로젝트 디렉토리 )
[RCTBridgeModule swift 클래스 구현] ReactNative 프로젝트 Root > ios > .xcworkspace을 xcode로 엽니다. swift 파일을 생성하기 위해 프로젝트 디렉토리 내에서 우클릭 하여 New File을 클릭하고 클래스 이름을 작성합니다.
생성된 swift파일에 GreenpOfferwall SDK의 Native 코드를 호출하기 위한 RCTBridgeModule을 구현 한 클래스의 내용을 작성합니다.
import Foundation
import React
import GreenpOfferwall
@objc(GreenpModule) // ModuleName ex)GreenpModule
class GreenpModule: NSObject, RCTBridgeModule {
private lazy var greenp = GreenPSettings(delegate: **self**)
private var callback: RCTResponseSenderBlock?
static func moduleName() -> String! {
return "GreenpModule"
}
@objc
func initialized(_ appCode: String, userId: String, callback: @escaping RCTResponseSenderBlock){
greenp.set(appCode: appCode, userID: userId)
self.callback = callback
}
@objc
func show(){
DispatchQueue.main.async {
if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = scene.windows.first,
let viewController = window.rootViewController {
self.greenp.show(on: viewController)
}
}
}
}
extension GreenpModule : GreenPDelegate {
func greenPSettingsDidEnd(with message: String) {
if let reply = callback {
if message == "Device Regist Success!" {
reply(["true", message])
}else {
reply(["false", message])
}
}
}
}
[RCTBridgeModule swift 클래스를 Objective-C로 연결하는 implementation File (.m) 구현] RCTBridgeModule을 구현 했던 swift 클래스에 작성한 인터페이스에 맞추어 Objective-C 프로토타입 인터페이스를 작성합니다.
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(GreenpModule, NSObject)
RCT_EXTERN_METHOD(show)
RCT_EXTERN_METHOD(initialized:(NSString *)appCode userId:(NSString *)userId callback:(RCTResponseSenderBlock)callback)
@end
Native 코드를 호출하기 위한 기본 설정이 완료되었다면, 다음과 같이 ReactNative 코드로 GreenpOfferwall SDK를 호출 할 수 있습니다.
import { ... , NativeModules,} from 'react-native';
export default function App() {
if(Platform.OS === 'android') {
NativeModules.GreenpModule.initialized('Your Code', 'User ID', (result: string, message: string) => {
if(result) {
//초기화 성공
} else {
//초기화 실패
}
});
} else if(Platform.OS === 'ios'){
NativeModules.GreenpModule.initialized('Your Code', 'User ID', (result, message) => {
if(result) {
//초기화 성공
}else {
//초기화 실패
}
});
}
}
※ 유저 구분값 생성 규칙
- 각각의 유저별 고유한 값을 이용해야 합니다.
- 개인정보 및 IDFA는 사용할 수 없습니다. ( 암호화 후 사용 가능 )
- 한글, 특수문자, 공백은 반드시 URL 인코딩 후 사용하셔야 합니다.
NativeModules.GreenpModule.show();
광고 참여가 정상적으로 완료된 경우, 매체사에서 등록 하신 콜백 URL로 암호화키를 전송해 드립니다.
CallBack url : 매체사 URLMethod : GET or POST (기본은 GET 방식이나 요청시 POST 방식으로도 가능합니다.
Ad Parameter | Type | 설명 |
---|---|---|
ads_idx | int |
광고키 |
ads_name | string |
갬페인 타이틀 |
rwd_cost | int |
매체사에 지급되는 단가 |
app_uid | string |
매체사에 보낸 유저 구분 값 (UserID) |
gp_key | int |
전환 건에 대한 유니크 값 |
etc | int |
referrer 값. 매체용 추가 정보(매체 uniq 클릭값 등) etc 대신 원하는 파라미터로 변경가능 |