안드로이드

[Android] 인앱 개발에 대해 알아보자 (실전)

코딩하는후운 2022. 10. 20. 14:12
반응형

Android 인앱 개발에 대해 알아보자

인앱 실전!!

1. SDK/extras/google/play_billing/IInAppBillingService.aidl
	-aidl파일 복사
2. SDK/extras/google/play_billing/samples/TrivialDrive/src/com/example/android/trivialdrivesample/util
	-util파일 복사
	
3. 복사 폴더위치
프로젝트/apps/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
프로젝트/apps/src/main/java/com/yj/consulting/inapp/(util파일들)

4. AndoridManifest.xml 수정
<uses-permission android:name="com.android.vending.BILLING" />

5. Application 클래스에 함수추가
/**
 * Init in app module
 */
public void initInAppModule(Context context, final Handler handler) {

	String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZIi+2MLODlyPPBBWFUR8L2cIunftjqy297JvSVXrCTpPTTFfRWn35DB59dUSvRWdEby2hhLyYS0UScTEFpLHAIAJmxyOOH/r8Gj6KMp9QGRoi/BSk9Bdy34TTRZ8zXKRGcaZxqfoBUCFXvX4PZCDYA+hbZG9gPNAFEJRY3marYM6kjLen/Lov0yn1CnoXjkQnlpK/XVAOMYiyXvdwN2rWofpnpQ07ROQsco8/XMIzRQBwsMaoEdBoDDIUjN/ywD/+magGQtiiVZTBApDtPB5kbAlNGLLM3eh7BNsgV9r813g96WdeACP0R8lUx/x7gWu6HBe7uWJ9TAi7193HtESwIDAQAB";

	m_iabHelper = new IabHelper(context, base64EncodedPublicKey);
	
	//로그 보여줄지 안보여줄지 (true:보여줌, false:안보여줌)
	m_iabHelper.enableDebugLogging(false);
	
	// startSetup함수를 호출함으로서 현재 통신가능여부를 확인하고, 정상적으로 커넥션이 이루어졌는지 확인할 수 있다.
	m_iabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
		public void onIabSetupFinished(IabResult result) {

			Message message = new Message();
			message.obj = result;

			handler.sendMessage(message);
		}
	});
}


6. IntroActivity.java onCreate에 인앱 결제 모듈 초기화
// 입앱 결제 모듈 초기화
if (!Build.BRAND.equalsIgnoreCase("generic")) {
	showProgress("", "잠시만기다려주세요");
	m_app.initInAppModule(this, new Handler() {

		@Override
		public void handleMessage(Message msg) {
			IabResult result = (IabResult) msg.obj;
			if (!result.isSuccess()) {

				hideProgress();
				m_hndSleep.sendEmptyMessageDelayed(0, 3000);

				Log.d(TAG, "In-app Billing setup failed: " +
						result);

				// Oh noes, there was a problem.
//              complain("Problem setting up in-app billing: " + result);
			} else {
				Log.d(TAG, "In-app Billing is set up OK");
				// IAB is fully set up. Now, let's get an inventory of stuff we own.
				Log.d(TAG, "Setup successful. Querying inventory.");
				
				// 성공적으로 연결이 되었다면 이제 실질적인 아이템을 로드해야한다.
				m_app.m_iabHelper.queryInventoryAsync(mGotInventoryListener);
				/*
					// 실제 아이템목록을 받아올 수 있음.
					// mItems에 올바른 값이 할당되어야 함.
					// 만약 mItems가 null값이라면 queryInventoryAsync메소드는 콜백이 호출될때 성공했다고 나오지만
			        // 어떠한 아이템 리스트 값도 받아올 수 없음.
					//mHelper.queryInventoryAsync(true, mItems, mGotInventoryListener);
				*/
			}
		}
	});
} else {
	//3초후 화면전환
	m_hndSleep.sendEmptyMessageDelayed(0, 3000);
}




7. // 실제 아이템목록을 받아올 수 있음.
	// mItems에 올바른 값이 할당되어야 함.
	// 만약 mItems가 null값이라면 queryInventoryAsync메소드는 콜백이 호출될때 성공했다고 나오지만
	// 어떠한 아이템 리스트 값도 받아올 수 없음.
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
	@Override
	public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
		// IabResult 값에는 다양한 에러코드및 성공여부를 담고 있음.
		// Inventory : 가져온 util클래스에서 제공하는 클래스. 아이템리스트를 갖고 있다.
		
		Log.d(TAG, "Query inventory finished.");

		// Have we been disposed of in the meantime? If so, quit.
		if (m_app.m_iabHelper == null) {
			hideProgress();
			registerDevice();
			return;
		}

		// Is it a failure?
		if (result.isFailure()) {
			hideProgress();
			registerDevice();
//                complain("Failed to query inventory: " + result);
			return;
		}

		Log.d(TAG, "Query inventory was successful.");

		/*
		 * Check for items we own. Notice that for each purchase, we check
		 * the developer payload to see if it's correct! See
		 * verifyDeveloperPayload().
		 */

		// 구매되고 소진되지 않은 아이템을 캐시해놓을 변수.
		List<Purchase> purchases = new ArrayList<Purchase>();

		// Check for gas delivery -- if we own gas, we should fill up the tank immediately
		//전화, 제안하기, 등록하기 아이템 등록
		Purchase purchase = inventory.getPurchase(SKU_CALL);
		if (purchase != null && verifyDeveloperPayload(purchase)) {
			purchases.add(purchase);
		}
		purchase = inventory.getPurchase(SKU_CONSULTING_SUGGEST);
		if (purchase != null && verifyDeveloperPayload(purchase)) {
			purchases.add(purchase);
		}
		purchase = inventory.getPurchase(SKU_SALE_REGISTER);
		if (purchase != null && verifyDeveloperPayload(purchase)) {
			purchases.add(purchase);
		}

		/*
			구입물 소비를 기록하기 위해, consumeAsync(Purchase, OnConsumeFinishedListener) 를 IabHelper 인스턴스에서 호출해야한다.
			메소드의 첫번째 인자는 소비될 아이템을 나타내는 Purchase 오브젝트이다. 두번째 인자는 OnConsumeFinishedListener 리스너로 소비 작업이 완료되고 구글플레이로 부터 소비 응답을 받아 다룰수 있는 경우 통지받게 된다. 
			mHelper.consumeAsync(inventory.getPurchase(SKU_GAS), mConsumeFinishedListener);
		*/
		if (purchases.size() > 0) {
			Log.d(TAG, "I have sign up purchase. Consuming it.");
			m_app.m_iabHelper.consumeAsync(purchases, mConsumeMultiFinishedListener);
			return;
		}

		hideProgress();
		registerDevice();
		Log.d(TAG, "Initial inventory query finished; enabling main UI.");
	}
};


8. 당신은 인앱 빌링 버전3의 API를 사용하여 구글플레이에서 구매된 소유물을 추적할 수 있다.
IabHelper.OnConsumeMultiFinishedListener mConsumeMultiFinishedListener = new IabHelper.OnConsumeMultiFinishedListener() {
	@Override
	public void onConsumeMultiFinished(List<Purchase> purchases, List<IabResult> results) {
		hideProgress();
		for (int i = 0; i < results.size(); i++) {
			IabResult result = results.get(i);
			if (result.isSuccess()) {
				//(인앱 제품을 유저에게 지급한다)
				//(예를들어 50Gold의 코인을 플레이어 캐릭터에 지급)

				Toast.makeText(m_app, "Consume success", Toast.LENGTH_SHORT).show();
			} else {
				// handle error
//                            complain("Error while consuming: " + result);
			}
		}
		registerDevice();
	}
};


9.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
	Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
	if (m_app.m_iabHelper == null) return;

	// Pass on the activity result to the helper for handling
	if (!m_app.m_iabHelper.handleActivityResult(requestCode, resultCode, data)) {
		// not handled, so handle it ourselves (here's where you'd
		// perform any handling of activity results not related to in-app
		// billing...
		super.onActivityResult(requestCode, resultCode, data);
	} else {
		Log.d(TAG, "onActivityResult handled by IABUtil.");
	}
}



===============================================

10.사용 액티비티에서 (SuggestActivity.java)
//onCreate에 추가
// 입앱 결제 모듈 초기화
showProgress("", getString(R.string.please_wait));
m_app.initInAppModule(this, new Handler() {

	@Override
	public void handleMessage(Message msg) {
		IabResult result = (IabResult) msg.obj;
		if (!result.isSuccess()) {
			Log.d(TAG, "In-app Billing setup failed: " + result);

			// Oh noes, there was a problem.
//                    complain("Problem setting up in-app billing: " + result);
		} else {
			Log.d(TAG, "In-app Billing is set up OK");
			// IAB is fully set up. Now, let's get an inventory of stuff we own.
			Log.d(TAG, "Setup successful. Querying inventory.");
		}

		hideProgress();


		// 의뢰내용을 가져온다. (화면 UI데이터들)
		getRequestDetail();
	}
});


11. 버튼클릭이벤트 (구매)
/**
 * 제안하기 처리를 진행한다.
 */
public void onSuggest(View view) {
//        if (m_nSelectedRentIndex == -1 && m_nSelectedPremiumIndex == -1 &&
//                !m_ivCheck[0].isSelected() && !m_ivCheck[1].isSelected()) {
//            Toast.makeText(this, R.string.please_select_option, Toast.LENGTH_SHORT).show();
//            return;
//        }

	//처음엔 null로 인앱 결제 실행
	if (m_purchase == null) {
		// 인앱 결제를 진행한다.

		m_app.m_iabHelper.flagEndAsync();
		//인앱에서 구매요구 시작하기위해 호출
		/*
			(첫번쨰 인자는 호출하는 액티비티다.)
			(두번째 인자는 구매할 제품의 ID다(또한 SKU라 불려진다)
				재품의 이름이 아닌 제품의 ID를 제공하는 지 확인해야한다. 반드시 이전에 개발자 콘솔에서 아이템을 선언하고 할성화 시켜야한다, 그렇지 않을경우 그것은 인정되지 않을것이다.)
			(세번째 인자는 요청 코드 값이다 이것은 임의의 양의 정수 값이 될 수 있다. 구글 플레이는 구매 응답시 Activity 의 onActivityResult 호출할때 요청코드를 되돌려준다.)
			(네번째 인자는 구매 작업이 완료될때 통지 받는 리스너다, 구글 플레이로 부터 구매 응답을 받아 다룬다.)
			(5번쨰 인자는 '개발자 payload' 스트링을 담고 있다, 당신은 주문에 대한 추가정보를 담아 보낼 수 있다(이것은 빈문자열이 될수있다). 일반적으로, 
				이것은 구매 요청의 유일한 식별자를 담는 스트링 토큰으로 전될되는데 사용된다. 만일 스트링 값을 지정하는 경우, 구글플레이는 구매 응답과 함께 스트링을 되돌려준다.
				이어서, 이 구매에 대해 조회할때, 구글 플레이는 응답 상세 정보에 스트링을 함께 포함하여 되돌려준다.) 
		*/
		m_app.m_iabHelper.launchPurchaseFlow(this, SKU_CONSULTING_SUGGEST, RC_REQUEST, mPurchaseFinishedListener, "mypurchasetoken");
		return;
	}


	// 서버요청 파라메터들을 설정한다.
	RequestParams p = new RequestParams();
	p.put("r", REQ_SUGGESTCONSULTING);
	p.put("consultant_no", m_app.m_loginUser.userNo);
	p.put("request_no", getIntent().getIntExtra("request_no", 0));
	if (m_nSelectedRentIndex == -1) {
		p.put("min_rent", 0);
		p.put("max_rent", 0);
	} else {
		p.put("min_rent", m_nSelectedRentIndex == 0 ? 0 : (m_nSelectedRentIndex * 5 + 1));
		p.put("max_rent", (m_nSelectedRentIndex + 1) * 5);
	}
	if (m_nSelectedPremiumIndex == -1) {
		p.put("min_premium", 0);
		p.put("max_premium", 0);
	} else {
		p.put("min_premium", m_nSelectedPremiumIndex == 0 ? 0 : (m_nSelectedPremiumIndex * 5 + 1));
		p.put("max_premium", (m_nSelectedPremiumIndex + 1) * 5);
	}
	p.put("is_consultation_possible", m_ivCheck[0].isSelected() ? 1 : 0);
	p.put("is_etc_possible", m_ivCheck[1].isSelected() ? 1 : 0);

	HttpRequestHelper.showProgress(this, "",
			getString(R.string.please_wait));
	HttpRequestHelper.get("", p, new JsonHttpResponseHandler() {
		@Override
		public void onSuccess(int statusCode, Header[] headers,
							  JSONObject response) {
			HttpRequestHelper.hideProgress();
			HttpRequestHelper.ResponseResult result = HttpRequestHelper.checkResultValue(
					m_app, response);
			if (result.res_value == 0) {
				Intent i;
//                    if (getIntent().getStringExtra("from").equals("SuggestPossibleRequestListActivity")) {
//                        i = new Intent(SuggestActivity.this, SuggestPossibleRequestListActivity.class);
//                    } else {
				i = new Intent(SuggestActivity.this, SuggestedRequestListActivity.class);
//                    }
				i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
				startActivity(i);
				finish();
			} else if (result.res_value < 1000) {
				Toast.makeText(m_app, R.string.server_problem,
						Toast.LENGTH_SHORT).show();
			}
		}

		@Override
		public void onFailure(int statusCode, Header[] headers,
							  Throwable throwable, JSONObject errorResponse) {
			HttpRequestHelper.hideProgress();
			Toast.makeText(m_app, R.string.data_fetch_error,
					Toast.LENGTH_SHORT).show();
		}
	}, m_app);
}


12. 구매 주문이 성공한다면, 구글플레이로부터의 응답 데이터는 Purchase 오브젝트를  담아 리스너에 전달된다.
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() 
{
	public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
	{
		// if we were disposed of in the meantime, quit.
		if (m_app.m_iabHelper == null) {
			return;
		}

		if (result.isFailure()) {
//                complain("Error purchasing: " + result);
//                Toast.makeText(m_app, "Error purchasing: " + result, Toast.LENGTH_SHORT).show();
			switch (result.getResponse())
			{
				case -1005:
					Log.d(TAG, "Cancel");
					break;
				default:
					Log.d(TAG, "Failed");
					break;
			}

			return;
		}
		if (!verifyDeveloperPayload(purchase)) {
//                complain("Error purchasing. Authenticity verification failed.");
//                Toast.makeText(m_app, "Error purchasing. Authenticity verification failed.", Toast.LENGTH_SHORT).show();
			return;
		}


		Log.d(TAG, "Purchase successful.");

		m_purchase = purchase;

		showProgress("", getString(R.string.please_wait));
		//구입물 소비
		m_app.m_iabHelper.consumeAsync(m_purchase, mConsumeFinishedListener);
	}
};


13. 소비완료후 서버요청
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
	public void onConsumeFinished(Purchase purchase, IabResult result) 
	{
		hideProgress();
		onSuggest(null);
	}
};

 

 

참조 : 

http://choi98772.blogspot.kr/2013/10/purchasing-in-app-billing-products-4.html

반응형