ReactNative GreenpOfferwall SDK 가이드 - rnd-adforus/GreenpSDK_Android GitHub Wiki

ReactNative GreenpOfferwall SDK 가이드는 Native로 개발되어 있는 GreenpOfferwall SDK를 ReactNative 환경에서 적용 가능하도록 구성된 샘플 코드 가이드 입니다. 다음의 구현 사항을 준수한 샘플 앱 다운로드 경로로 샘플 코드 적용을 확인 할 수 있습니다. ReactNative - GreenpOfferwall SDK Sample

바로가기

  1. 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 호출 필수 설정
  2. SDK 초기화
  3. SDK 사용법
  4. 콜백 URL 파라미터 설정

1. Platform 별 초기 세팅

1-1. AOS

(1) build.gradle 설정

최소 지원 Android 버전은 ReactNative 프로젝트 > android > build.gradle 을 열고 의존성 Maven url을 설정합니다.

allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
        maven{
            url 'https://nexus.adforus.com/repository/greenp/'
        }
        maven { // Optional - 오퍼월 내 구글 광고를 사용하시려면 작성 해주세요!
            url 'https://artifact.bytedance.com/repository/pangle/'
        }
    }
}

ReactNative 프로젝트 > android > app > build.gradle 을 열고 의존성 목록을 추가합니다.

android {
    viewBinding{
        enabled = true
    }
}
dependencies {
    ...
     // 가이드 문서 내 최신버전 참고
    implementation 'com.adforus.sdk:greenp_v3:3.5.2'
    implementation 'com.adforus.sdk:adsu:1.2.0' // Optional - 오퍼월 내 구글 광고를 사용하시려면 작성 해주세요!
}

(2) AndroidManifest.xml 설정

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>

(3) Proguard 설정

ReactNative 프로젝트 > android > app > proguard-rules.pro 에 다음을 추가하여 난독화 시 구현에 필요한 인터페이스의 난독화가 되지 않도록 설정해주세요.

-keep class com.adforus.sdk.greenp.v3.** { *; }
-dontwarn com.adforus.sdk.greenp.v3.**

-keep class com.adforus.sdk.adsu.** {*;}
-dontwarn com.adforus.sdk.adsu.**

(4) Native Interface 호출 필수 설정

React-Native에서는 Android Native 코드 호출을 위해 NativeModule을 사용합니다. NativeModule사용을 위한 단계는 다음과 같습니다.
  • 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() {
                // 복수의 오퍼월을 게시 하기 위해서는 다음의 코드를 사용해주세요.
                // GreepReward greenpReward = new GreewnpReward(); 
                // greenpReward.initialize(Context context, String appCode, String appUid, GreenpReward.OnGreenpRewardListener listener);

                    @Override
                    public void onResult(boolean result, String msg) {
                        sendResult(result, msg, appCode);
                    }
                });
            }else {
                GreenpReward.init(reactContext.getCurrentActivity(), appCode, userId, new GreenpReward.OnGreenpRewardListener() {
                // 복수의 오퍼월을 게시 하기 위해서는 다음의 코드를 사용해주세요.
                // GreepReward greenpReward = new GreewnpReward(); 
                // greenpReward.initialize(Activity activity, String appCode, String appUid, GreenpReward.OnGreenpRewardListener listener);
                    @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();
                // 복수의 오퍼월을 게시 하기 위해서는 다음의 코드를 사용해주세요.
                // builder = greenpReward.createOfferwallBuilder();
                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 수동 등록
            }
         ... 생략 ...
      }
   ... 생략 ...
}

1-2. iOS

(1) Installation 설정

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 'GreenPOfferWall', '3.4.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

(2) Info.plist 설정

광고 추적 권한 허용 여부에 사용 되는 문구 설정 및 오퍼월 광고 지원을 위한 api 통신 설정이 다음과 같이 필요합니다. 다음의 설정이 올바르지 않을 시 오퍼월 리워드 지급이 원활하지 않을 수 있습니다. ReactNative 프로젝트 Root > ios > YourProject.xcworkspace을 xcode로 열고 Info.plist에 다음과 같이 추가 설정합니다.

광고 추적 권한에 따른 문구 설정
권한 요청 문구
http 통신 예외처리
통신 예외 처리

(3) Native Interface 호출 필수 설정

React-Native에서는 iOS Native 코드 호출을 위해 NativeModule을 사용합니다. NativeModule사용을 위한 단계는 다음과 같습니다.
  • 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

2. SDK 초기화

Native 코드를 호출하기 위한 기본 설정이 완료되었다면, 다음과 같이 ReactNative 코드로 GreenpOfferwall SDK를 호출 할 수 있습니다.

init 호출

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 {
	        //초기화 실패
        }
      });
  }
}

※ 유저 구분값 생성 규칙

  1. 각각의 유저별 고유한 값을 이용해야 합니다.
  2. 개인정보 및 IDFA는 사용할 수 없습니다. ( 암호화 후 사용 가능 )
  3. 한글, 특수문자, 공백은 반드시 URL 인코딩 후 사용하셔야 합니다.

5. SDK 사용법

Offerwall 호출

	NativeModules.GreenpModule.show();

6. 파라미터 콜백 설정

광고 참여가 정상적으로 완료된 경우, 매체사에서 등록 하신 콜백 URL로 암호화키를 전송해 드립니다.

CallBack url : 매체사 URL
Method : 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 대신 원하는 파라미터로 변경가능
⚠️ **GitHub.com Fallback** ⚠️