React-Native

리액트 네이티브 모듈 sdk 붙이기 (안드로이드 스튜디오) - adiscope

hyriver(강화영) 2025. 5. 18. 16:16

네이티브 모듈로 애디스쿱 sdk붙이는 연습을 해보았다

참고로 java를 모르는 사람이기에 생성자를 만들어야하는 것도 코드 짜면서 알게 되어서 중간중간 내용이 뜬금없을 수 있다.. ^-^

 

android/app/src/main/java/com/…/패키지파일명

여기서 모듈파일과 패키지 파일을 생성한다(java)

모듈파일

초기화

미디어 id와 시크릿 key를 등록하고, 광고 실행 시키기 전 준비 작업

AdiscopeSdk.initialize(Activity activity, AdiscopeInitializeListener listener)
// activity와 listener라는 2개의 매개변수를 받음
  • Activity
    • 현재 앱의 화면을 나타내는 객체 → sdk는 화면 전환이나 ui를 제어할 필요가 있으므로 현재 화면이 뭔지 알아야하기때문
    • ReactApplicationContext의 getCurrentActivity()로 현재 화면 즉, activity를 얻을 수 있다
  • Listener
    • 리스너는 이벤트 발생 후 호출되는 콜백함수이다. 여기서는 애디스콥 초기화(=이벤트) 결과에 따라 다르게 실행시킬 수 있다
    ReactApplicationContext reactContext;
    
    AdiscopeSdk.initialize(reactContext.getCurrentActivity(), new AdiscopeInitializeListener() {
        @Override
        public void onInitialized(boolean isSuccess) {
            if (isSuccess) {
    		    // 광고 인스턴스 생성 및 광고 이벤트 리스너 연결
    		    mRewardedVideoAd = AdiscopeSdk.getRewardedVideoAdInstance(reactContext.getCurrentActivity());
                mRewardedVideoAd.setRewardedVideoAdListener(mRewardedVideoAdListener());
            } else {
                // Init 실패 에 대한 처리 Code 
            }
        }
    }
    • ReactApplicationContext는 앱 전체에 대한 정보를 가지고 있는 객체로 Native Module에서 js와의 상호작용을 위해 사용하는 메서드들을 가지고 있다(sendEvent 등)
    • onInitialized의 매개변수 isSuccess는 초기화 리스너의 콜백함수 매개변수로 초기화가 실행되면 내부 로직에 따라 알아서 초기화 되고 결과를 isSuccess로 넘겨준다

자동 import 안되는 에러

  • 원래 공식문서 코드 그대로 붙이면 안드로이드 스튜디오에서 import 안된 건 빨갛게 표시되면서 자동으로 import 할수있게 되어있다

근데 import된 게 없어도 빨갛게 표시가 안됨

이상하다 싶었지만 그냥 npm run android 돌려버림

Cannot resolve symbol 'RewardedVideoAd'
create class RewardedVideoAd

 

sdk를 gradle에 추가하고 Gradle Sync를 해야하는데 안했다고함

→ 안드로이드 스튜디오 메뉴 File > Sync Project with Gradle Files 클릭

 

🚫 The project is using an incompatible version (AGP 8.8.2) of the Android Gradle plugin. Latest supported version is AGP 8.1.3

 

했더니 이렇게 뜬다

 

→ 버전 차이로 안드로이드 스튜디오를 업데이트 하기

https://dev-ej2.tistory.com/67

 

안드로이드 스튜디오 버전 업데이트 방법 (+기린 giraffe 새로운 UI 적용)

안드로이드 스튜디오 버전이 전기뱀장어였는데, 기린으로 업데이트를 해보았다. 1. Check for Updates... 를 클릭하여 업데이트 할 버전이 있는지 확인한다. 2. 홈페이지에서 최신 버전을 다운받는다.

dev-ej2.tistory.com

 

나는 M2 Apple 칩 탑재 Mac이라 android-studio-2024.3.2.14-mac_arm.dmg 로 다운로드

 

 

👉 최신버전의 안드로이드 스튜디오에서는 잘 뜬다

 

 

패키지 파일

public class AdiscopePackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
      List<NativeModule> modules = new ArrayList<>();
      modules.add(new AdiscopeModule(reactContext));
      return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
      return Collections.emptyList();
    }
  }

에러발생

modules.add(new AdiscopeModule(reactContext));

이 부분에서 에러

 

→ 알고보니 모듈 파일의

public class adiscopeModule extends ReactContextBaseJavaModule {

이렇게 클래스명이 소문자로 되어있었다 ^^; 그래서 대문자로 이름 변경

 

 

modules.add(new AdiscopeModule(reactContext));

이번엔 reactContext에서 에러발생

 

🚫 Expected no arguments but found 1

 

→ 생성자를 만들어 줘야 했는데 안 만들었다 ^^;

public AdiscopeModule(ReactApplicationContext context) {
    super(context);            // 부모 클래스인 ReactContextBaseJavaModule에 context 전달
    reactContext = context;    // 현재 context를 필드에 저장
}

 

생성자를 만들었더니 js에서 RNAdiscope를 로그에 찍으면 출력이 된다.

하지만 초기화 함수는 실행되지 않는데..

 

초기화 실패

  useEffect(() => {
    RNAdiscope.initializeAdiscope();
  }, []);
  1. 앱 실행 시 초기화시키도록 했으나 initializeAdiscope를 못찾음..

 

@Override
public String getName() {
  return "RNAdiscope";
}
  • 기본사항인 getName을 맞추지 않았다^^;
  1. initializeAdiscope는 실행되지만 초기화가 실패함

 

[Android Studio] 패키지 이름 바꾸기

아래 보여지는 디렉터리 구조를 펼쳐서 보기위해 설정을 먼저 변경해줍니다.1\. 변경할 폴더 명에서 우클릭 - Refactor - Rename을 클릭합니다.2\. All Directories를 누릅니다. 3\. 변경할 이름을 입력 후 Re

velog.io

 

 

  • npm run android 했더니 또 새로운 에러

 

🚫 INSTALL_FAILED_VERSION_DOWNGRADE: Downgrade detected: Update version code 1 is older than current 126

 

  • 에뮬레이터에서 앱을 삭제해준다 👉 adb uninstall 패키지이름

→ 성공!

set user id

유저 아이디를 애디스콥에 전달해주는 작업

@ReactMethod
public void setUserId(String userId) {
    AdiscopeSdk.setUserId(userId);
}
  • @ReactMethod → 아래의 함수는 리액트에서 사용할 수 있는거라고 선언하는 것
    • js에서 네이티브 코드 사용할 수 있도록

→ 초기화는 앱 실행 시, 유저 아이디 저장은 앱 실행 시와 id가 변경됐을 때 수행된다

 

 

여기까지는 광고 사전 작업!


실제 광고 연결 작업

일단 리스너를 설정해줘야 한다. 공식문서에 나와있는 onRewardedVideoAdLoaded, onRewarded 이런 이벤트 콜백함수들은 위에 인스턴스 생성할 때 넣은 mRewardedVideoAdListener() 이 리스너 안에 정의해준다.

public RewardedVideoAdListener mRewardedVideoAdListener() {
	return new RewardedVideoAdListener() {
	
		@Override
		public void onRewardedVideoAdLoaded(String unitId) {
		  // 광고 가져오기 성공 시
		}
		
		// ...
		
		@Override
		public void onRewarded(String unitId, RewardItem rewardItem) {
			// 사용자가 광고를 끝까지 시청하여 보상을 받을 자격이 생겼을 때
		}
	}
}

1. Load

광고를 보여주기 전, 보여줄 광고들을 가져온다. load가 성공하면 리스너의 onRewardedVideoAdLoaded, 로드 실패 시 onRewardedVideoAdFailedToLoad 콜백 함수가 호출된다

// 광고 다운로드(load) 시작
@ReactMethod
public void loadRewardedAd(String unitId) {
	if (mRewardedVideoAd != null) {
		mRewardedVideoAd.load(unitId);
		Log.e(TAG, "보상형 광고 로드 완료");
	} else {
		Log.e(TAG, "보상형 광고 로드 실패");
	}
}
  • unitId는 정해진 아이디가 있다! 이것도 내맘대로 id했다가 시간 엄청 보냄..

2. Show

들고온 광고들을 보여 준다. mRewardedVideoAd.show() 는 리스너의 onRewardedVideoAdLoaded에 넣는다. 성공 시 onRewardedVideoAdOpened, onRewarded 실패 시 onRewardedVideoAdFailedToShow 이벤트 콜백 호출.

@Override
public void onRewardedVideoAdLoaded(String unitId) {
	// 광고가 로드 성공 시
	mRewardedVideoAd.show();
	Log.d(TAG, "aos : 보상형 광고 로드 성공 -> show 까지");
}

3. 리스너에 있는 콜백함수를 js에서 사용하고 싶을 때

네이티브에서 정의한 로드 실패 시 호출, 광고 종료 시 호출하는 것을 리액트에서도 알아차리고 뭔가 작업하고 싶은 뭔가가 있을 때는 sendEvent를 사용한다

private void sendEvent(String eventName,  @Nullable WritableMap params) {
	reactContext
		.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
		.emit(eventName, params);
}
@Override
public void onRewarded(String unitId, RewardItem rewardItem) {
	// 사용자가 광고를 끝까지 시청하여 보상을 받을 자격이 생겼을 때
	// RewardItem.getType: 보상 타입
	// RewardItem.getAmount: 보상 양
	WritableMap rewardData = Arguments.createMap();
	rewardData.putString("type", rewardItem.getType());
	rewardData.putInt("amount", (int)  rewardItem.getAmount());

	sendEvent("onRewarded");  //이렇게 정의된 이벤트명을 js에서 사용할 수 있다
	Log.d(TAG, "보상받기 완료");
}
const onRewardedListener = adiscopeEmitter.addListener('onRewarded', () => {
    Alert.alert('보상 완료', '리워드 보상이 완료되었습니다.');
        onRewardedListener.remove();
});
//onRewarded가 호출될 때 리워드 보상 alert창이 뜨도록

 

js에서 네이티브 코드의 실행결과를 알 필요가 없으면? 안해줘도 된다

 

 

onRewarded에서 타입과 보상 js로 보내기

WritableMap rewardData = Arguments.createMap();
rewardData.putString("type", rewardItem.getType());
rewardData.putInt("amount", (int)  rewardItem.getAmount());
  • js로 데이터를 보내기 위해 Map 객체를 만든다 → rewardData
  • rewardItem.getType()에서 타입을, rewardItem.getAmount()에서 보상 양(숫자)을 가져와 저장한다
  • sendEvent에 같이 넣어준다
sendEvent("onRewarded", rewardData);  //이렇게 정의된 이벤트명을 js에서 사용할 수 있다
  • js에서는 아래와 같이 타입과 개수를 사용할 수 있다
      const onRewardedListener = adiscopeEmitter.addListener('onRewarded', (data) => {
    Alert.alert(
      '보상 완료',
      data.type + '타입, ' + data.amount + '개 보상 지급',
    );
        onRewardedListener.remove();
      });

 

 

 

  • 종종 안될때는 gradlew을 삭제시켜주기
cd android
./gradlew clean
cd ..
npm install

 

 


 

자바도 그렇고 안드로이드도 익숙하지 않아서 애먹었지만 리액트 네이티브 모듈이 어떻게 작동하고, sdk 연결해서 사용하는 것의 구조를 파악할 수 있었다. 앞으로 자바도 안드로이드도 점차 공부해나가야지.