2.2.2
IOS
RNIAP API๋ฅผ ์ฌ์ฉํ์ฌ ์๋ ๊ฐฑ์ ๊ตฌ๋ ์ด ์ฌ์ ํ ํ์ฑ ์ํ์ธ์ง ํ์ธํ ์ ์์ต๋๋ค.
Android์์ ๋ค์์ ํ์ธํ๊ธฐ ์ํด ๋ค์์ ์ํํฉ๋๋ค.
export const isUserSubscriptionActive = async (subscriptionId) =>{
// Get all the items that the user has
const availablePurchases = await getAvailablePurchases();
if(availablePurchases !== null && availablePurchases.length > 0){
const subscription = availablePurchases.find((element)=>{
return subscriptionId === element.productId;
});
if(subscription){
// check for the autoRenewingAndroid flag. If it is false the sub period is over
return subscription["autoRenewingAndroid"] == true;
}
}else{
return false;
}
}
}
ios์๋ ์ด๋ฅผ ํ์ธํ๋ ํ๋๊ทธ๊ฐ ์์ผ๋ฉฐ getAvailablePurchases ๋ฉ์๋๋ ํ์ฌ ํ์ฑํ๋์ง ์์ ๊ตฌ๋ ์ ํฌํจํ์ฌ ์ด๋ฃจ์ด์ง ๋ชจ๋ ๊ตฌ๋งค๋ฅผ ๋ฐํํฉ๋๋ค.
์ด๊ฒ์ ํ์ธํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
๋ฌธ์ ์ธ์ฌ,
๋ง๋ฅด์ฝ์ค
๋๋ ์ด๊ฒ์ ์์๋ด๊ธฐ ์ํด ๋
ธ๋ ฅํ๊ณ ์๋ค. ์์ง ํ
์คํธํ์ง ์์์ง๋ง ๋ด๊ฐ ์ฝ์ ๋ด์ฉ์์ iTunes Connect์์ "๊ณต์ ๋น๋ฐ"์ ๋ง๋ค๊ณ '๋น๋ฐ๋ฒํธ' ํค๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ validateReceiptIos์ ์ ๋ฌํ๋ฉด ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ์์งํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ๊ตฌ๋
์ ์ ํจ์ฑ ๊ฒ์ฌ ์ํ๋ฅผ ๋ํ๋ด๋ ์ฝ๋์ ํนํ ๊ตฌ๋
์ํ๋ฅผ ํ์ธํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ latest_receipt, latest_receipt_info ๋ฐ latest_expired_receipt ์ ๋ณด๊ฐ ํฌํจ๋ JSON ๊ฐ์ฒด๊ฐ ๋ฐํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๋ฌธ์ ๊ทธ๋๋ก ์ด๊ฒ์ ์์ ๋ด๊ณ ์์ผ๋ฏ๋ก ์์ง ํ
์คํธํ์ง ์์์ต๋๋ค. ๋ฌธ์ ์ Apple์ ๋ฌธ์๋ฅผ ๋ชจ์ ๋์ ๊ฒ์
๋๋ค. ์ด๊ฒ์ด ํจ๊ณผ๊ฐ ์๋ค๋ฉด ๋ฌธ์ ์ ๋ฌปํ์ง ์๊ณ ๋ฌธ์์์ ๋งค์ฐ ๋ช
ํํ๊ฒ ๋ฐํ์ผ ํฉ๋๋ค.
๋ค์ ๋งํฌ๊ฐ ๊ด๋ จ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
ํธ์ง : ์์์ ์ธ๊ธํ ํ๋ก์ธ์ค๊ฐ ์๋ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค. ๋๋ ์ฐ๋ฆฌ๊ฐ ๋ฌธ์์์ ์ด๊ฒ์ ๋ํ ์์ ํ ์ค๋ช ์ ์ป๊ธฐ ์ํด ๋ ธ๋ ฅํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๊ตฌ๋ ์ด ๋ง๋ฃ๋์๋์ง ํ์ธํ๊ธฐ ์ํด ์ฑ ์์ ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํฉ๋๋ค.
RNIap.getPurchaseHistory()
.then(purchases => {
RNIap.validateReceiptIos({
//Get receipt for the latest purchase
'receipt-data': purchases[purchases.length - 1].transactionReceipt,
'password': 'whateveryourpasswordis'
}, __DEV__)
.then(receipt => {
//latest_receipt_info returns an array of objects each representing a renewal of the most
//recently purchased item. Kinda confusing terminology
const renewalHistory = receipt.latest_receipt_info
//This returns the expiration date of the latest renewal of the latest purchase
const expiration = renewalHistory[renewalHistory.length - 1].expires_date_ms
//Boolean for whether it has expired. Can use in your app to enable/disable subscription
console.log(expiration > Date.now())
})
.catch(error => console.log(`Error`))
})
@kevinEsherick
ํ๋ฅญํ!
๊ทํ์ ์ฝ๋์ ๋ํด ๊ทธ๋ค์ง ์ฌ์ํ์ง ์์ ๋ช ๊ฐ์ง ์ฌํญ;
const ๋ง๋ฃ = ๊ฐฑ์ ๊ธฐ๋ก [renewalHistory.length - 1].expires_date_ms
๋์ (์๋ง๋ ๊ทธ๋ฅ ์คํ)
const ๋ง๋ฃ = latestRenewalReceipt [latestRenewal.length - 1].expires_date_ms
2) '๋น๋ฐ๋ฒํธ'๊ฐ ๋ฌด์์ธ์ง ๋ชจ๋ฅด๋ ๋ถ๋ค์ ์ํด: '๋น๋ฐ๋ฒํธ๊ฐ ๋ฌด์์ด๋ ':
์ธ์ฑ ํ์ด์ง์ ๋ํ ๊ณต์ ๋น๋ฐ ํค๋ฅผ ๋ง๋ค๊ณ ์ฑ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. https://www.appypie.com/faqs/how-can-i-get-shared-secret-key-for-in-app-purchase
+1 ๋ฌธ์ ์ ๋ฐ์ดํธ, ๋ํ @dooboolab IOS์ Android์์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋ถ๋ฆฌํ ์ ์์ผ๋ฉฐ ๋ช ๊ฐ์ง ๋ค๋ฅธ ์ ์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ํ์๋ฉด ๋์๋๋ฆด ์ ์์ต๋๋ค.
๋ฌธ์ ์ธ์ฌ
@kevinEsherick
์๋ ๊ฐฑ์ ๊ตฌ๋ ์ ์ด๋ป๊ฒ ๋ฉ๋๊น?
expires_date_ms๊ฐ ์ฒซ ๋ฒ์งธ ๋ง๋ฃ ๋ ์ง์ธ ๊ฒ ๊ฐ์ผ๋ฉฐ ์ ๋ฐ์ดํธ๋์ง ์์์ต๋๋ค.
๋๋ ์ด๊ฒ์ ํ ์คํธํ๋ค :
์ด๋ค ์์ด๋์ด?
๋ด ๋์, ๋ง๋ฃ ๋ ์ง๊ฐ ์ ๋ฐ์ดํธ ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋จ์ง ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
๋๊ตฐ๊ฐ๊ฐ ๊ฐ์ ์๋๋ฆฌ์ค์ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ์ฌ๊ธฐ์ ์ด โโ์๊ฒฌ์ ๋จ๊ธธ ๊ฒ์ ๋๋ค.
๋ฌธ์ ์ธ์ฌ
- ๊ทธ๊ฒ์ํด์ผํ๋ค
const ๋ง๋ฃ = ๊ฐฑ์ ๊ธฐ๋ก [renewalHistory.length - 1].expires_date_ms
๋์ (์๋ง๋ ๊ทธ๋ฅ ์คํ)
const ๋ง๋ฃ = latestRenewalReceipt [latestRenewal.length - 1].expires_date_ms
์ ๋ง๋ค, ์คํ๊ฐ ๋ง์๋ค. ๊ทธ ์๋ฏธ๋ฅผ ๋ ๋ช ํํ๊ฒ ํ๊ธฐ ์ํด ์ด๋ฆ์ ๋ณ๊ฒฝํ์ง๋ง ๋ชจ๋ ํญ๋ชฉ์ ๋ณ๊ฒฝํ๋ ๊ฒ์ ์์์ต๋๋ค. ์์ ํ์ต๋๋ค, ๊ฐ์ฌํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง๋ฃ ๋ ์ง๊ฐ ์๋ ์ ํํ ์๋๋ฆฌ์ค๋ ์์์ง๋ง ์๋ ๊ฐฑ์ ์ด ์ ํ ๋์ง ์๋ ์ผ๋ถ ํญ๋ชฉ์ด ์์์ง๋ง ์์ฒด์ ์ผ๋ก ํด๊ฒฐ๋์์ต๋๋ค(๊ฑฑ์ ๋์ง๋ง ์ฌ์์ฐํ ์ ์์ผ๋ฏ๋ก ๋ค๋ฅธ ์์ ์ ์ํํด์ผ ํจ). ๋น์ ์ด ๊ฐ์ง ๋ฌธ์ ๋ ์๋นํ ์ผ๋ฐ์ ์ธ ๋ฌธ์ ์ ๋๋ค. Apple ์ธก์์ ์์ํ ๋์์ด๋ฏ๋ก ์ฌ์ฉ์๋ฅผ ๊ตฌ๋ ์ทจ์ํ๊ธฐ ์ ์ ๊ตฌ๋ ์ด ๊ฐฑ์ ๋ ์ ์๋๋ก ๋ฒํผ ๊ธฐ๊ฐ์ ๋จ๊ฒจ ๋์ด์ผ ํฉ๋๋ค. SO์ ๋ํ ์ด ๋ฌธ์ ๋ https://stackoverflow.com/questions/42158460/autorenewable-subscription-iap-renewing-after-expiry-date-in-sandbox ์์ ์์ธํ ์ค๋ช ํฉ๋๋ค.
๊ฐ์ฌ ํด์! ์ข์ ์ ๋ณด, ์ด์ ๊ฐ ๋ ์ ์์ต๋๋ค
์ด ๋ฌธ์ ์ ๋ํด @kevinEsherick ์ฝ๋๊ฐ ๋ฌธ์์ ์์ด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค
์. PR
์์ฒญํ๋ ์ฌ๋์ด ์์ผ๋ฉด readme
์ ๊น๋ํ ๋ฌธ์๋ฅผ ๋ณด๋ด์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๊ฐ์ฌ ํด์.
์๋
์๋ค์. Readme์ Q & A ์น์
์ ์ถ๊ฐํ์ต๋๋ค. ๋๊ตฌ๋ ์ง ์ด ๋ฌธ์ ์ ๋ํด PR
๋ฅผ ์ ๊ณตํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๋ฉฐ์น ๋ด๋ก PR์ ํ ์ ์๋๋ก ๋ ธ๋ ฅํ๊ฒ ์ต๋๋ค. :)
๋๋ ๋ํ ํนํ ๊ตฌ๋ ์ ์ํด ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํฉ๋๋ค. iOS์ ์๋๋ก์ด๋ ๋ชจ๋. ์ฌ์ฉ์์๊ฒ ์ ํจํ ๊ตฌ๋ ์ด ์๋์ง ํ์ธํ๋ ์ ์ ํ ๋ฐฉ๋ฒ์ ๋ฌธ์ํํ๋ฉด ๋๋จํ ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๐
@curiousdustin ์ด์ ๋ํ Apple์ ๊ตฌํ์ medium ์ ์ฐธ์กฐํ๋ฉด ์ ๋ง ๋์ฐํฉ๋๋ค. ๋ฐฑ์๋์์ ์ด๋ฌํ ์ข
๋ฅ์ ์์
์ ์ฒ๋ฆฌํด์ผ ํ๋ฏ๋ก ๋ชจ๋์์ ์ด๋ฅผ ์์ ํ ์ง์ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ iOS ๊ตฌ๋
์ ํ์์๋ ์๋ํ์ง ์๋ getAvailablePurchases
๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ Android์์ availablePurchases
๋ฅผ ์ป์ ์ ์์ต๋๋ค.
๊ทธ๋์ @marcosmartinez7 ๊ณผ @kevinEsherick ์ด ์ด ์ค๋ ๋์์ ์์ ํ๊ณ ์๋ ์๋ฃจ์ ์ด ์๋ฃจ์ ์ด ์๋๋ฉฐ iOS ๊ตฌ๋ ์ํ๋ฅผ ํ์ธํ๊ธฐ ์ํด Apple ์ด์ธ์ ๋ฐฑ์๋ ์๋ฒ๊ฐ ํ์ํ๋ค๋ ์ ๊ฐ์ ?
Apple ๋ฌธ์์ ํจ๊ป ๊ฒ์ํ Medium ๊ธฐ์ฌ๋ฅผ ๋ณด๋ฉด ์๋ฒ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ํธ๋๋ ๊ฒ ๊ฐ์ง๋ง ์ฅ์น๋ง์ผ๋ก ๊ตฌ๋ ์ํ๋ฅผ ํ์ธํ๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ ๊ฒ์ ์๋๋๋ค.
์ ๊ธ์ ์ ๋ณด๊ฐ ๋๋ฝ๋ ์ ์ฃ์กํฉ๋๋ค. ์ง๊ธ ๊ด๋ฆฌํ๊ฒ ์ต๋๋ค.
Apple
๋ ์ค๊ฐ ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด receipt
๋ฅผ ์์ ์ ์๋ฒ์ ์ ์ฅํ๋ ๊ฒ์ ์ ์ํฉ๋๋ค. ๋ฐ๋ผ์ ๋์ค์ ์์์ฆ์ ํ์ธํ์ฌ ์์์ฆ์ด ์ ํจํ์ง ๋๋ ๊ตฌ๋
์ ๊ณ์ ์ฌ์ฉํ ์ ์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ๊ฐ์ฌํ๊ฒ๋ @marcosmartinez7 ๊ณผ @kevinEsherick์ด ํด๊ฒฐํ ์์ฒด Apple ์๋ฒ(์๋๋ฐ์ค ๋ฐ ํ๋ก๋์
)์ ๊ฒ์ฆ ์์์ฆ์ ์ง์ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ react-native-iap
๋ก ๊ณ์ ์๋ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ์ง ์์ต๋๋ค.
ํ์ฌ ์ด๊ฒ์ด ios
๊ตฌ๋
์ ํ์ธํ๊ธฐ ์ํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์๋ ํ์ธ์, ์ฃ์กํฉ๋๋ค. ๋ฉฐ์น ์ด์ ์ง๋ฌ์ต๋๋ค. ์ผ์ ๋ชฐ๋ํ์ง๋ง ์ฌ์ ํ README๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ ์ํด ํด๋น PR์ ์ ์ถํ ๊ฒ์ ๋๋ค. @curiousdustin ์์์ ๋ด๊ฐ ์ด ๋ฐฉ๋ฒ์ ํ์คํ ํจ๊ณผ๊ฐ ์์ผ๋ฉฐ ๋ฌธ์์ ์ถ๊ฐํ๊ฒ ์ต๋๋ค. ์ค๋ ๋ฐค์ด๋ ๋ด์ผ PR ํ ๊ฒ์ :)
์ ๋ฐ์ดํธ ๊ฐ์ฌํฉ๋๋ค.
๋น์ ์ ์์์ ํ ๊ฐ์ง ๋ ๊นจ๋ฌ์์ต๋๋ค.
'์์์ฆ ๋ฐ์ดํฐ': ๊ตฌ๋งค[purchases.length - 1].transactionReceipt,
...
const ๋ง๋ฃ = ๊ฐฑ์ ๊ธฐ๋ก[renewalHistory.length - 1].expires_date_ms
๋ด ํ ์คํธ์์ ๊ตฌ๋งค ๋ฐ ๊ฐฑ์ ๊ธฐ๋ก์ด ๋ฐ๋์ ํน์ ์์๋ ์๋๋๋ค. ์ฐ๋ฆฌ๊ฐ ์๋ํ ๊ฒ์ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํ๊ธฐ ์ํด ๊ทธ๊ฒ๋ค์ ์ ๋ ฌํ๊ฑฐ๋ ๋ญ๊ฐ๋ฅผ ํด์ผ ํ์ง ์์๊น์?
์ฌ๊ธฐ๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ๊ตฌ๋งค ๋ฐ ๊ฐฑ์ ๊ธฐ๋ก์ ํ์คํ ์ฃผ๋ฌธ๋์ง ์์ผ๋ฏ๋ก ๋จผ์ ์ ๋ ฌํด์ผ ํฉ๋๋ค. dev์์๋ ๋ง์ ๋ฐ๋ณต์ด ํ์ํฉ๋๋ค.
๋ค์์ Android์ iOS ๋ชจ๋์์ ์๋ํ๋ฉฐ ์ต์ ์์์ฆ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๋๋ก iOS์์ ์ ์ ํ๊ฒ ์ ๋ ฌํ๋ ๊ธฐ๋ฅ์ ๋๋ค.
import * as RNIap from 'react-native-iap';
import {ITUNES_CONNECT_SHARED_SECRET} from 'react-native-dotenv';
const SUBSCRIPTIONS = {
// This is an example, we actually have this forked by iOS / Android environments
ALL: ['monthlySubscriptionId', 'yearlySubscriptionId'],
}
async function isSubscriptionActive() {
if (Platform.OS === 'ios') {
const availablePurchases = await RNIap.getAvailablePurchases();
const sortedAvailablePurchases = availablePurchases.sort(
(a, b) => b.transactionDate - a.transactionDate
);
const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;
const isTestEnvironment = __DEV__;
const decodedReceipt = await RNIap.validateReceiptIos(
{
'receipt-data': latestAvailableReceipt,
password: ITUNES_CONNECT_SHARED_SECRET,
},
isTestEnvironment
);
const {latest_receipt_info: latestReceiptInfo} = decodedReceipt;
const isSubValid = !!latestReceiptInfo.find(receipt => {
const expirationInMilliseconds = Number(receipt.expires_date_ms);
const nowInMilliseconds = Date.now();
return expirationInMilliseconds > nowInMilliseconds;
});
return isSubValid;
}
if (Platform.OS === 'android') {
// When an active subscription expires, it does not show up in
// available purchases anymore, therefore we can use the length
// of the availablePurchases array to determine whether or not
// they have an active subscription.
const availablePurchases = await RNIap.getAvailablePurchases();
for (let i = 0; i < availablePurchases.length; i++) {
if (SUBSCRIPTIONS.ALL.includes(availablePurchases[i].productId)) {
return true;
}
}
return false;
}
}
@andrewze
Android ์๋๋ฆฌ์ค์์ ๊ตฌ๋ ์ด ์๋ ๊ฐฑ์ ๊ฐ๋ฅํ ๊ฒฝ์ฐ availablePurchases์ ๋ฐํ๋ฉ๋๋ค.
@curiousdustin @andrewzey ๋ง์ต๋๋ค. ๊ตฌ๋งค๋ ์ฃผ๋ฌธ๋์ง ์์ต๋๋ค. ํ์ง๋ง, RenewalHistory/latest_receipt_info๋ ํญ์ ์ ๋ฅผ ์ํด ์ฃผ๋ฌธ๋ฉ๋๋ค. ๊ตฌ๋งค๊ฐ ์ฃผ๋ฌธ๋์ง ์์๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ง๋ง ์ด๊ฒ์ด ์ค์ ๋ก ๋ฌธ์ ๊ฐ ๋์ง ์๋ ์ด์ ๋ฅผ ์ฐพ์๋ค๊ณ ์๊ฐํ์ต๋๋ค. ์ง์ ๋์ฐฉํ๋ฉด ๋ช ์๊ฐ ํ์ ์ด ๋ฌธ์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋๋ ์ฐ๋ฆฌ๊ฐ ์ด๊ฒ์ ์์๋ผ ๋๊น์ง PR์ ์ ์ถํ๊ณ ์ถ์ง ์์ต๋๋ค.
ํธ์ง: ๋ฐ๋ผ์ ๊ตฌ๋งค๋ฅผ ์ ๋ ฌํ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํ๋ ์ด์ ๋ ๊ทํ๊ฐ ์ฟผ๋ฆฌํ ๊ตฌ๋งค์ ๊ด๊ณ์์ด expires_date_ms๊ฐ ๋์ผํ๊ฒ ๋ฐํ๋๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด๊ฒ์ ์ฌ๋ฌ๋ถ๋ ๋ง์ฐฌ๊ฐ์ง๊ฐ ์๋๋๊น? ์๋๋ฉด ์ ๋ ฌ์ด ํ์ํ ์ฝ๊ฐ์ ์ ๋ณด๊ฐ ํ์ํฉ๋๊น? ๋ค ์๊ฐ์ ๋งํด๋ด. ๋๋ ๋ฌธ์๊ฐ ๊ตฌ๋งค๊ฐ ์๊ฐ์์ผ๋ก ์ ๋ ฌ๋์ง ์๋๋ค๋ ์ ์ ์ฌ์ ํ ๋ถ๋ช
ํ ํด์ผ ํ๋ค๋ ๋ฐ ๋์ํ์ง๋ง, ๋ด๊ฐ ๋งํ ์ ์๋ ํ ๋ง๋ฃ ๋ ์ง๋ฅผ ์ป๊ธฐ ์ํด ์ ๋ ฌ์ด ํ์ํ์ง ์์ต๋๋ค.
@kevinEsherick ๊ฐ์ฌํฉ๋๋ค! ์ ๊ฒฝ์ฐ์๋ ๊ตฌ๋งค ๋๋ ๊ฐฑ์ ๊ธฐ๋ก์ด ์ฃผ๋ฌธ๋์ง ์์์ต๋๋ค.
@kevinEsherick @andrewzey ์ด ์๋ฃจ์
์ PR
๋ฅผ ์ค ์ ์์ต๋๊น? ๊ณ ํต๋ฐ๋ ๋ค๋ฅธ ์ด๋ค๊ณผ ๋๋๊ณ ์ ํฉ๋๋ค.
๋ฌผ๋ก ๊ณต๊ฐ ์ฑ ์ถ์๊ฐ ์๋ฃ๋๋ ์ฆ์ ์ค๋นํ๊ฒ ์ต๋๋ค =).
๋๋ ๋์ ๋ง์ง๋ง ์ฝ๋ฉํธ์ ๊ดํด ๋ ๋ง์ ๋ํ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์๋ค. ํด๊ฒฐ๋์ง ์์ ๋ช ๊ฐ์ง ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ์ต๋๋ค. ์ฐธ๊ณ ๋ก ์๋ฅผ ๋ด์ฃผ์ธ์. ์ผ๋จ ์ฐ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ์ ๋ฆฌํ๋ฉด ์ฐ๋ฆฌ ์ค ํ ๋ช ์ด PR์ ํ ์ ์์ต๋๋ค.
@kevinEsherick ์ ์ฃ์กํฉ๋๋ค. ๋์ณค์ต๋๋ค.
expires_date_ms
๋ ๊ฐ ๊ฐฑ์ ์์์ฆ์์ ํ์คํ ๊ณ ์ ํฉ๋๋ค. ์ ๊ฐ ์๋ชป ์ดํดํ ๊ฒ์ ์๋๊น์? ๋์ฝ๋ฉ๋ ๊ฐ ์์์ฆ์ ์ฒจ๋ถ๋ ๊ฐฑ์ ์์์ฆ ๋ฐฐ์ด์ ์ด๋ค ์์์ฆ์ด ์ ํ๋์๋์ง์ ๊ด๊ณ์์ด ๋์ผํ๋ฏ๋ก ํ์ํ์ง ์์ ๋ค์(๋ด ์์์)์ด ์ณ์ ์ ์์์ ์ ์ ์์ต๋๋ค.
const sortedAvailablePurchases = availablePurchases.sort(
(a, b) => b.transactionDate - a.transactionDate
);
๊ทธ๋ฌ๋ ๋๋ ์ ํํ๋ ค๊ณ ๋ ธ๋ ฅํ๊ณ Apple ๋ฌธ์์์ ์ค์ API ์๋ต์ ๊ฐ๋ฅํ ๋ถ์ผ์น๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ๊ทธ๋ ๊ฒ ํ์ต๋๋ค. ์๋ ๊ฐฑ์ ๊ตฌ๋ ์ ๋ํด ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ์๋ ์ด ์์์ฆ ์๋ฅผ ๊ณ ๋ คํ ๋ ์ ๋ ฌ ์์ ์ด ๋งค์ฐ ๋น์ฉ์ด ๋ง์ด ๋ค ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ง ์์ต๋๋ค.
PR์ ETA๊ฐ ์์ต๋๊น? ์ด ํจํค์ง ๋ ์ด ๊ฒฝ์ฐ๋ฅผ ์ ํ ์ฒ๋ฆฌํ์ง ์๊ธฐ ๋๋ฌธ์
@schhumannd PR์ด ๋ฌธ์๋ฅผ ์
๋ฐ์ดํธํ๋ ๊ฒ์ผ ๋ฟ react-native-iap
๋ก ์ด๋ํ ์ ์์ต๋๋ค.
์ต๊ทผ ์ถ์๋ ์ฑ์์ ๋ด ์ฝ๋ ์ค๋ํซ์ด ์ค์ ๋ก ๋ฌธ์ ์์ด ์๋ํจ์ ํ์ธํ์ต๋๋ค. https://itunes.apple.com/us/app/rp-diet/id1330041267?ls=1&mt=8
ํธ์ง ํ์คํ PR์ ํ๊ฒ ์ง๋ง(Trello์ "Give back to OSS" ๋ชฉ๋ก์ ์์), ๋ธ๋ ํ๋ผ์ด๋ฐ์ด ์ฃผ๋ง ๊ด๋ ์ดํ ๐
@schhumannd ์ ๋ @andrewzey๊ฐ ๋งํ ๋ ๋ฒ์งธ์ ๋๋ค. PR์ด ๋งํ๋ ๋ชจ๋ ๊ฒ์ด ์ด ๊ฒ์๋ฌผ์ ํฌํจ๋์ด ์์ต๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๊ณ ํ์ง๋ง ์ํํด์ผ ํ ์์ ์ ์ ํํ ์ ๋ฆฌํ๋ ๋ฐ ์๊ฐ์ด ๊ฑธ๋ ธ๊ณ ์ฌํ๊ณผ ๋ฐ์ ์์ ์๊ฐ์ด ๋ค์์ฌ์ ์์ง ํ๋ณดํ ์๊ฐ์ด ์์์ต๋๋ค. ๋๋ ์ฌ์ ํ ๊ณง ํ ๊ณํ์ด์ง๋ง, ์ํ๋ ๊ฒฝ์ฐ ๋ค๋ฅธ ์ฌ๋์ด ๊ทธ ๋์ ๋จ๊ณ๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ @andrewzey ์ถํํฉ๋๋ค ! ๋ฉ์ ธ๋ณด์ด๋ค์ ๋ค์ด๋ฐ๊ฒ ์ต๋๋ค!
์ด ์ค๋ ๋๊ฐ iOS์์ ์๋ ๊ฐฑ์ ๊ตฌ๋ ์ ๊ด๋ฆฌํ๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ์ ํํ๊ฒ ๋ฌธ์ํํ๋์ง ํ์ ํ ์ ์์ง๋ง ๋์ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ํด ๋ ธ์ถ๋ API์ ๋ฐ๋ผ "ํด๊ฒฐ ๋ฐฉ๋ฒ" ์ํฌํ๋ก๋ฅผ ์ค๋ช ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ ์ ์ ์ผ๋ก ๋ด ์ถ์ธก์ด๋ฉฐ ๋ด๊ฐ ํ๋ฆด ์ ์์์ ์ ์๊ณ ์์ผ๋ฏ๋ก ์๋์ ์ค๋ช ๋ ๊ด์ฐฐ์ ๋ํ ํผ๋๋ฐฑ์ ๋ฐ๊ณ ์ถ์ต๋๋ค.
๋๋ ๋ช ์ฃผ ๋์ React Native์์ ์๋ ๊ฐฑ์ ๊ตฌ๋ ์ ๊ด๋ฆฌํ๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ์ฐ๊ตฌํ์ง๋ง ์๋ฌด ์์ฉ์ด ์์์ต๋๋ค. ๊ทธ๋์ ๊ธฐ์ด๋ฅผ ์ ํํ๊ณ Objective-C/Swift์์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ตฌ๋ ์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ฐ๊ตฌํ๊ธฐ ์์ํ์ต๋๋ค. ์ด๊ฒ์ ๋์๊ฒ ๋ค์ดํฐ๋ธ StoreKit API์ ๋ฌธ์ํ๋ ์ฌ์ฉ๋ฒ์ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ตฌํ๋ ๊ฒ๊ณผ ๋น๊ตํ ์ ์๋ ์ฐธ์กฐ ์ง์ ์ ์ ๊ณตํ์ต๋๋ค.
์ด ๊ธ์ ๊ธฐ๋ณธ iOS ์ฑ์์ ๊ตฌ๋
๊ตฌ๋งค, ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ๋ณต์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ง๊ธ๊น์ง ์ฐพ์ ์ต๊ณ ์ ์ค๋ช
์
๋๋ค. https://www.raywenderlich.com/659-in-app-purchases-auto -renewable-subscriptions-tutorial ๋ฐ ๋ชจ๋ API๊ฐ react-native-iap
์์ ์ฌ์ฉ๋๋ ๋์ ๋ค๋ฅธ ์ํฌํ๋ก๋ฅผ ๊ตฌํํ๊ณ ์์ต๋๋ค.
๋ด๊ฐ ๋ณด๋ ์ฃผ์ ์ฐจ์ด์ ์ appStoreReceiptUrl
์
๋๋ค.
StoreKit์ ๋ด ์ดํด์ ๋ฐ๋ผ iOS ์ฑ์ ๋ํ ํ์ฌ ๊ตฌ๋งค/์์์ฆ ์ ๋ณด๋ฅผ ๋ก๋ํ๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ธ appStoreReceiptUrl
๋ฅผ ์ ๊ณตํฉ๋๋ค. react-native-iap
์ฝ๋์์ ์ด๊ฒ์ด ์ฌ์ฉ๋๊ณ ์ฐธ์กฐ๋๋ ๊ฒ์
์ด ๊ตฌํ ์ฐจ์ด๊ฐ ๋ฌธ์ ๊ฐ ์๋์ง ์ฌ๋ถ๋ ํ์คํ์ง ์์ง๋ง react-native-iap
API๋ ๊ฒฐ๊ตญ getPurchaseHistory
์ํด ํธ์ถ๋๋ StoreKit์ restoreCompletedTransactions
์ ๋ถํ์ํ ์ข
์์ฑ์ ์์ฑํ๋ ๊ฒ ๊ฐ์ต๋๋ค getPurchaseHistory
.
react-native-iap
API๋ iOS์ ๋ํด ๋ค์ ์ํฌํ๋ก๋ฅผ ์ง์ํด์ผ ํฉ๋๋ค.
appStoreReceiptUrl
)appStoreReceiptUrl
๊ฐ null์ธ ๊ฒฝ์ฐ ํ์ฌ ์ฅ์น์์ "๋ณต์"์ ์์ํ ๋ค์ appStoreReceiptUrl
๊ฐ์ ์ค์ ํ๊ณ ์ ํจ์ฑ ๊ฒ์ฌ ๋
ผ๋ฆฌ๋ฅผ ๋ค์ ์๋ํ ์ ์์ต๋๋ค.์๊ฐ?
๋ค์ ๋งํ์ง๋ง, ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ตฌํ ๋๋ ์ฐธ์กฐ๋ ๊ธฐ๋ณธ ๊ตฌํ์ ์คํดํ ์ ์์ต๋๋ค.
@sellmeadog
๊ทํ๊ฐ ๋งํฌํ ๊ธฐ์ฌ์์๋ ์ธ๊ธ๋ ์์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ฐธ๊ณ : ํ๋ก์ ํธ ์ฑ์ ์์์ฆ์ ์๋ฝํ๊ณ Apple์ ์์์ฆ ํ์ธ ์๋น์ค์ ์ง์ ์ ๋ก๋ํ๋ SelfieService๋ฅผ ์คํํฉ๋๋ค. ์ด๊ฒ์ ํํ ๋ฆฌ์ผ์ด ๊ตฌ๋ ์ค์ ์ ์ง์คํ๋๋ก ํ๋ "์นํธ"์ ๋๋ค. ์ค์ ์ฑ์์๋ ์ฑ์ด ์๋ ์๊ฒฉ ์๋ฒ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ ์ฒด ์๋ ๊ฐฑ์ ๊ตฌ๋ ์ ํ์ ํ๋ ๋ฐ ์๊ฐ์ด ๊ฑธ๋ ธ์ง๋ง ๋ด๊ฐ ์ดํดํ๋ ๊ฐ์ฅ ์ข์ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ๊ณ ์ ํ ๋ฐฑ์๋๋ฅผ ๋จ์ผ ์์ค๋ก ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
๋์๊ฒ ์ด๊ฒ์ ๊ตฌ๋ ์ ์ฒ๋ฆฌํ๋ ์ ์ผํ ์ ์ ์ ์ธ ๋ฐฉ๋ฒ์ฒ๋ผ ๋ณด์๋ค. ๋ํ ํ๋์ ์์ ์ ์ผ๋ก ์๋ ๊ฐฑ์ ๊ตฌ๋ ์ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ๊ฐ๋ฐ์์ ์ด ํ๋ก์ธ์ค๋ฅผ ํ์ธํ์ต๋๋ค.
๋ฐ๋ผ์ OP ์ง๋ฌธ์ ๋ํ ๋ด ๋๋ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ํ๋ก ํธ์๋๊ฐ ์๋ ๋ฐฑ์๋์์ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ตฌ๋ ์ ํ์ธํฉ๋๋ค.
@schumand
๊ฐ์ ๋ฌธ์ ๋ฅผ ์ดํดํ๊ฑฐ๋ ์ด์ผ๊ธฐํ๊ณ ์๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
์์์ฆ ์ ํจ์ฑ ๊ฒ์ฌ ๋ ์๋ฒ์์ ์ํํด์ผ ํฉ๋๋ค. Apple ์์ฒด ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด :
์ฑ์์ App Store ์๋ฒ
/verifyReceipt
์๋ํฌ์ธํธ๋ฅผ ํธ์ถํ์ง ๋ง์ญ์์ค.
๋๋ ์ฐธ์กฐ๋ ๊ธฐ์ฌ์ "์นํธ"๋ฅผ ๋ฐฑ์๋ ์๋ฒ์ ์์ํ๋ ๋์ ๊ฐ๊ฒฐ์ฑ์ ์ํด ์ฑ์์ ์ง์ /verifyReceipt
๋ํ ์ํ ์ฑ์ ์ง์ ํธ์ถ๋ก ํด์ํ์ต๋๋ค.
Apple/App Store๋ ์ง์ค์ ๋จ์ผ ์ถ์ฒ์ด๋ฉฐ ๊ทธ๋์ผ๋ง ํ๋ ๊ฒ ๊ฐ์ต๋๋ค. Apple์ ๊ถ๊ทน์ ์ผ๋ก ๊ตฌ๋งค, ๊ฐฑ์ , ์ทจ์ ๋ฑ์ ์ฒ๋ฆฌํ๊ณ ๊ทธ์ ๋ฐ๋ผ ์์์ฆ์ ์์ฑํ๊ณ StoreKit
API๋ฅผ ํตํด ํด๋น ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
react-native-iap
๋ ๋ฌธ์ ์์ด ๊ตฌ๋งค ๋ฐ ๊ตฌ๋งค ๋ณต์์ ์ฒ๋ฆฌํ์ง๋ง ์ฌ์ ํ Apple์ ๋ฌธ์ํ๋ ์์์ฆ ์ก์ธ์ค ๋ฐฉ๋ฒ์ธ appStoreReceiptUrl
์์ ๋ก์ปฌ๋ก ์ ๊ณต๋๋ App Store ์์์ฆ ๋ฐ์ดํฐ์ ์ก์ธ์คํ๋ ๋ฐ ๊ฒฉ์ฐจ๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ฐ์ดํฐ :
์์์ฆ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๋ ค๋ฉด
NSBundle
์appStoreReceiptURL
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ์ ์์์ฆ์ ์ฐพ์ต๋๋ค...
Apple ๋ฌธ์๋ฅผ ์ฝ๊ณ ๊ธฐ๋ณธ Object-C/Swift ๊ตฌํ์ ์ฐธ์กฐํ์ฌ ์ดํดํ ์ํฌํ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
appStoreReceiptUrl
์ํด StoreKit
appStoreReceiptUrl
์ ๋ก์ปฌ๋ก ์ ์ฅ๋ฉ๋๋ค./verifyReceipt
์๋ ์ง์ )๋ก ๋ณด๋ด์ผ ํฉ๋๋ค.appStoreReceiptUrl
๋ ์ทจ์ ๋ฐ/๋๋ ๊ฐฑ์ ์ด ๋ฐ์ํ ๋๋ง๋ค StoreKit
appStoreReceiptUrl
๋ก ์
๋ฐ์ดํธ๋ฉ๋๋ค(์ ์ ํ StoreKit
๋๋ฆฌ์ธ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ฑ๋ก๋์๋ค๊ณ ๊ฐ์ ).appStoreReceiptUrl
๊ฐ null์ธ ๊ฒฝ์ฐ ์ฌ์ฉ์๊ฐ ์ ์ฅ์น ๋ฑ์ ์ฌ์ฉ ์ค์ด๊ธฐ ๋๋ฌธ์ Apple/AppStore์์ ํ์ฌ ์์์ฆ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๊ณ StoreKit
๊ฐ appStoreReceiptUrl
์์ ๋ก์ปฌ๋ก ์ ์งํ๋ ๋ณต์ ๊ตฌ๋งค ์ํฌํ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค ๋ค์ react-native-iap
๋ appStoreReceiptUrl
์์ ์์์ฆ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋ ๊ฒ์ ์ ์ธํ๊ณ ์ด ๋ชจ๋ ๊ฒ์ ์ฒ๋ฆฌํฉ๋๋ค. ํ์ง ์์์ฆ์ ์กฐํํ๋ getReceipt
๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ๊ตฌ๋
๋ฐ/๋๋ ๊ธฐํ ๊ตฌ๋งค๋ฅผ ๊ด๋ฆฌํ๋ ๋ถ๋ด์ ๋ ์ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ ํ์ ์ด๊ฒ์ ์๊ฐ๋ณด๋ค ํจ์ฌ ๋ ์ด๋ ต๊ฒ ๋ง๋ค์๋ค.
appStoreReceiptUrl
๋ ์ทจ์ ๋ฐ/๋๋ ๊ฐฑ์ ์ด ๋ฐ์ํ ๋๋ง๋คStoreKit
appStoreReceiptUrl
๋ก ์ ๋ฐ์ดํธ๋ฉ๋๋ค(์ ์ ํ StoreKit ๋๋ฆฌ์ธ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ฑ๋ก๋์๋ค๊ณ ๊ฐ์ ).
์ด๊ฒ์ ๋ด๊ฐ ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ํด ๊ฐ์ง๊ณ ์๋ ๋ฌธ์ ๋ฅผ ์ค๋ช ํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์ธํฐ๋ท ์ฐ๊ฒฐ์ด ์๋ํ๋ ์ํ์์ ์ดํ์ ์ฑ์ ์ด์ง ์์ผ๋ฉด ๊ฐฑ์ /์ทจ์/๋ง๋ฃ ๋ฑ์ ๋ํ ์๋ฆผ์ ๋ฐ์ง ๋ชปํฉ๋๋ค.
๊ทธ ์ธ์๋ ๋ด๊ฐ ์ค๋ช ํ ์ ๊ทผ ๋ฐฉ์์ ๋ํ ์ข์ ๋์์ธ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๋ค ๊ฒ์ด ํ๋ก๋์ ์ฑ์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋์ง ๊ถ๊ธํฉ๋๋ค.
@sellmeadog ๋๋ ๊ทธ๊ฒ์ด ๋ด๊ฐ ์ฌ๊ธฐ์ ๊ฒ์ํ ๊ฒ๊ณผ ๊ฐ์ ์๊ฐ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค: #356
ํ์ง์์ ์์์ฆ์ ํ์ธํ๋ ๊ฒ๋ ํ ๊ฐ์ง ๋ฐฉ๋ฒ์ด๋ผ๊ณ Apple์ ๊ถ์ฅํฉ๋๋ค. ์ด๋ ๋ชจ๋ ์๋ฒ/๋คํธ์ํฌ ์์ฒญ๊ณผ ์์ ํ ๋
๋ฆฝ์ ์
๋๋ค.
๋ค. "๋คํธ์ํฌ ์ฐ๊ฒฐ ์์ - ์ ํจ์ฑ ๊ฒ์ฌ ์์"๊ณผ ๊ด๋ จ๋ ๋จ์ ์ด ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ด์ ๋ํ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์์ต๋๋ค.
๋ชจ๋ ์ฑ์ ์คํํ ๋๋ง๋ค ์์์ฆ์ ๋น ๋ฅด๊ฒ ํ์ธํ๊ณ UserDefaults
๋๋ Keychain
๋ฅผ ํตํด ์ธ์ฑ ๊ตฌ๋งค๋ฅผ ์ถ์ ํ๊ณ ์ถ์ง ์์ต๋๋ค. StoreKit
์ด๋ฏธ ์ ์ฅ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค.
IOS ์ฌ์ฉ์๊ฐ getAvailablePurchases์ ๊ฐ์ ๊ฒ์ ํตํด itunes ๊ณ์ ์ ๋ก๊ทธ์ธํ๋ผ๋ ๋ฉ์์ง๋ฅผ ํ์ํ์ง ์๊ณ ๊ตฌ๋ ์ ๊ฐฑ์ ํ๊ฑฐ๋ ์ทจ์ํ๋์ง ์ด๋ป๊ฒ ํ์ธํด์ผ ํฉ๋๊น?
์๋ฅผ ๋ค์ด:
๊ตฌ๋
์ ์ฒ์ ๊ตฌ๋งคํ ๋ ์์์ฆ์ ํ์ธํ๊ณ ๋ง๋ฃ ๋ ์ง๋ฅผ Firebase ํ๋กํ์ ์ ์ฅํฉ๋๋ค. ํด๋น Firebase ๋
ธ๋๋ฅผ ์ฌ์ฉํ์ฌ ํ์ฑํ๋ ๊ตฌ๋
์ด ์๋์ง ์์ ์ ํ์ธํฉ๋๋ค. ๋ฌธ์ ๋ ๋ง๋ฃ์ผ์ด ์ง๋๊ณ ์๋ก์ด ์ฒญ๊ตฌ ๊ธฐ๊ฐ์ด ์์๋ ๋ ๋ฐ์ํฉ๋๋ค. ์๋ ๊ฐฑ์ ๋๋ ์ทจ์๋์๋์ง ์ด๋ป๊ฒ ํ์ธํ ์ ์์ต๋๊น? ์ธ๊ธํ๋ฏ์ด ์ฐ๋ฆฌ๋ getAvailablePurchases๋ฅผ ์ฌ์ฉํ๊ณ ์์์ง๋ง ๋ณต์ ๋ฒํผ์ฒ๋ผ itunes ๋ก๊ทธ์ธ์ ํ๋กฌํํธํฉ๋๋ค. ์ด๊ฒ์ ๋์ฐํ UI์
๋๋ค.
์ ๋ ๊ฐ์๊ฒ ๊ถ๊ธํฉ๋๋ค.
์ฑ์์๋ ์ํ๋ฅผ ํ์ธํ๊ธฐ ์ํด Apple๊ณผ ์ง์ ํต์ ํ๋ ์๋ฒ ์ธก API๊ฐ ์์ผ๋ฏ๋ก ์ด ํญ๋ชฉ์ด ํ์ํ์ง ์์ต๋๋ค. ์ต์ด ๊ตฌ๋งค ํ ์์์ฆ ๋ฐ์ดํฐ๋ ๋น์ฌ ์๋ฒ์ ์ ์ฅ๋๊ณ ๋์ค์ ์ ๋ฐ์ดํธ๋ ์ํ๋ฅผ ์์ฒญํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
๊ทธ๋ฌ๋ ๋๋ ์ด๊ฒ์ด ์ฅ์น ์ธก๋ฉด์์ ์ฌ์ ํ ๊ฐ๋ฅํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ์ด์ ๋ํ ์ ๋ฌธ๊ฐ๋ ์๋์ง๋ง ๋ด๊ฐ ์ดํดํ๋ ๋ฐ์ ๋ฐ๋ฅด๋ฉด ์ฑ์ ๊ฐฑ์ ์ด ๋ฐ์ํ ๋๋ง๋ค OS์์ ์ ๋ฐ์ดํธ๋ ๊ฑฐ๋/์์์ฆ์ ๋ฐ์ต๋๋ค. ์ด ํ๋ฌ๊ทธ์ธ์ด ์ฑ ์คํ ์ ์ด๋ฌํ ์์์ฆ์ ์ฒ๋ฆฌํ๋ ๊ฒ ๊ฐ์ต๋๋ค. (Xcode์์ ์คํํ ๋ ์ฌ๋ฌ ํธ๋์ญ์ ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ ๋ง์ ๋ก๊ทธ๋ฅผ ๋ด ๋๋ค.) ํ์ง๋ง ์ ๊ฐ ์ ์ ์๋ ๋ฐ์ ๋ฐ๋ฅด๋ฉด JS ์ฝ๋์์ ์ด๋ฌํ ์ด๋ฒคํธ๋ฅผ ํ์ฉํ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
์ด๊ฒ์ ๋ํด ๋ ๋ง์ ์ ๋ณด๋ฅผ ์ป์ ์ ์์ต๋๊น?
@csumrell @curiousdustin ํ๋ก๋์ ํ๊ฒฝ์์ ์ด ๋์์ด ํ์ธ๋์์ต๋๊น? ์ฅ์น์ ์๋๋ฐ์ค๊ฐ ์๋ ๋ค๋ฅธ ๊ณ์ ์ด ์์ ์ ์์ผ๋ฏ๋ก ์๋๋ฐ์ค ๊ณ์ ์ ๋ก๊ทธ์ธํด์ผ ํ๋ ์๋๋ฐ์ค ๋๋ฌธ์ ๋ฐ์ํ ์ ์๋์ง ๊ถ๊ธํฉ๋๋ค. ๋ฐ๋ฉด ํ๋ก๋์ ์์๋ ์ฌ์ฉ์๊ฐ ์ผ๋ฐ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๊ณ ์ด ๋ชจ๋์ ๋ก๊ทธ์ธ์ ์๊ตฌํ์ง ์๊ณ getPurchases๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฃ์กํฉ๋๋ค. getAvailablePurchases()
๊ฐ ํ๋ก๋์
์์ ์ํธ ํ๋กฌํํธ๋ฅผ ์ ๋ฐํ๋์ง ํ์ธํ์ง ์์์ต๋๋ค.
๋ฌธ์์์ ์ผ๋ฐ์ ์ผ๋ก ๊ตฌ๋งค ๋ณต์์ด๋ผ๊ณ ํ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉ๋๋ ์ด ๋ฐฉ๋ฒ์ ๋ํด ์ด์ผ๊ธฐํ๊ธฐ ๋๋ฌธ์ ๊ทธ๋ด ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ์ต๋๋ค. ๋ด ๊ฒฝํ์ ๋ฐ๋ฅด๋ฉด ์ด ๋ฐฉ๋ฒ์ ์ ์ด๋ iOS์์ ์ธ์ฆ์ ํฌํจํฉ๋๋ค.
@hyochan @JJMoon ์ด๊ฒ๋ ์ข ๋
@curiousdustin ์ , ์ผ๋ฐ iTunes ๊ณ์ ์์ ๋ก๊ทธ์์ํ๊ณ ์๋๋ฐ์ค ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๋ฉด ์ด ๋ฉ์๋๊ฐ ํธ์ถ๋ ๋ ๋ ์ด์ ๋ก๊ทธ์ธํ๋ผ๋ ๋ฉ์์ง๊ฐ ํ์๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ด ์ถ์ธก/ํฌ๋ง์ ์ฌ์ฉ์๊ฐ ์ฌ์ฉ ์ค์ธ ์๋๋ฐ์ค ๊ณ์ ์ด ์๋ ํ๋ก๋์
ํ๊ฒฝ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์์ผ ํ๋ค๋ ๊ฒ์
๋๋ค. ๋ฒ ํ ํ
์คํธ๋ ์ฌ์ฉ์๊ฐ ์ฅ์น์ ์๋๋ฐ์ค ๊ณ์ ์ ์ค์ ํ์ง ์์ ๊ฒฝ์ฐ ํ๋ก๋์
๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ์๋ํด์ผ ํฉ๋๋ค. ์ด๋ ๊ฐ๋ฐ ์ฅ์น์ ๋ฌธ์ ์ผ ๋ฟ์
๋๋ค. ๊ทธ๋์ ๋ด์ผ ๋ฒ ํ ์ฌ์ฉ์์ ํจ๊ป ์ด๊ฒ์ ํ
์คํธํ๊ณ ๋ด๊ฐ ์ฐพ์ ๊ฒ์ ์๋ ค ๋๋ฆฌ๊ฒ ์ต๋๋ค.
ํธ์ง: ์๋๋ฐ์ค๊ฐ ์๋ ์ฅ์น์์ ์ด๋ฌํ ์ผ์ด ๋ฐ์ํจ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ๋์ฐํ UX์ด๋ฉฐ ์๋นํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋๊ตฌ, ์ด๋ค ์์ด๋์ด๋ผ๋?
๋ฐ๋ผ์ ์ฑ์์ App Store ์๋ฒ /verifyReceipt ์๋ํฌ์ธํธ๋ฅผ ํธ์ถํ์ฌ ์์ฒด ์๋ฒ์์ ์ ํจ์ฑ์ ๊ฒ์ฌํ ๋ ์๋์ ์ฒซ ๋ฒ์งธ ๊ตฌ๋งค ์์์ฆ๊ณผ ํจ๊ป ํด๋น ์ฌ์ฉ์์ ๋ํ ์ต์ ์ ๋ฐ์ดํธ ์ ๋ณด๋ฅผ ํญ์ ๋ฐํํฉ๋๋ค.
๋ก์ปฌ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ํญ์ ์ต์ ์ ๋ณด๋ ๋ฐํ๋๋์ง ์๋ ์ฌ๋์ด ์์ต๋๊น? ์๋๋ฉด ํด๋น ์์์ฆ์ ๋ํด์๋ง ๋ก์ปฌ์์ ํ์ธํ๋ ๊ฒ์ ๋๊น?
๋ํ Apple๊ณผ ํจ๊ป ์ ํจ์ฑ์ ๊ฒ์ฌํ๊ธฐ ์ํด ์์ฒด ์๋ฒ๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์กฐ์ธ์ด ์๋ ์ฌ๋์ด ์์ต๋๊น? ๋๋ ๊ทธ๊ฒ์ ๋ํ ๊ฒฝํ์ด ์๋ค
@csumrell getPurchaseHistory๋ฅผ ํธ์ถํ๊ณ ์ ๋ ฌํ์ฌ ์ต๊ทผ ๊ตฌ๋งค์ ๋ํ ์์์ฆ์ ์ป์ ์ ์์ต๋๋ค. ์์ ์ฃผ์์ ์ด ์์ ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ์ค๋ช ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์ต์ ์ ๋ณด๊ฐ ์์ด์ผ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ก๋ฅผ ๋์ธ ์ ์๋๋ก ์๋ฒ์์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ ์ต์ ์ ํ์ํ๋ ค๊ณ ํฉ๋๋ค. ๋ค๋ฅธ ์ฌ๋์ด ๊ทธ๊ฒ์ ๋ํด ์ด๋ป๊ฒ ๊ฐ๋์ง ๋ฃ๊ณ ์ถ์ต๋๋ค.
@kevinEsherick ์, ํ์ง๋ง getPurchaseHistory๋ Itunes ๋ก๊ทธ์ธ ํ์ ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์ฒ์ ๊ตฌ๋งคํ ๋ ์๋ณธ ์์์ฆ์ ๋ก์ปฌ ์ ์ฅ์์ ์ ์ฅํ๋ ๊ฒ์ ๋ํด ์ด์ผ๊ธฐํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ getPurchaseHistory๋ฅผ ํธ์ถํ์ฌ ๋ค์ ์ฒญ๊ตฌ๋ฅผ ํ์ธํ๋ ๋์ ๋ก์ปฌ์์ ๊ฒ์ฆ๋ validateReceiptIos(originalReceipt)๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๋ฌ๋ validateReceiptIos๊ฐ Apple ์๋ฒ /verifyReceipt์ ๊ฐ์ ์ต์ ํธ๋์ญ์ ์ ๋ฐํํ๋์ง ํ์คํ์ง ์์ต๋๋ค.
@csumrell ๊ฐ์ฑ . ๋น ๋ฅด๊ณ ์ฝ๊ฒ ํ
์คํธํ ์ ์์ต๋๋ค. ์์จ๋ดค์ด? ์๋๋ผ๋ฉด ์ค๋ ๋ฆ๊ฒ ํ์ธํ๊ฒ ์ต๋๋ค.
ํธ์ง: @csumrell validateReceiptIos๋ ์ค์ ๋ก ํด๋น ๊ตฌ๋งค์ ๋ํ ์ต์ ์๋ ๊ฐฑ์ ์ ์ถ์ ํ๋ฏ๋ก ์ด๊ฒ์ด ์ ํจํ ๋ฐฉ๋ฒ์
๋๋ค. ๋๋ ์ด๊ฒ์ด iTunes ๋ก๊ทธ์ธ ํ๋กฌํํธ๋ฅผ ํผํ๊ธฐ ๋๋ฌธ์ ๊ตฌ๋
์ ํ์ธํ๊ธฐ ์ํด ์์์ ์ ์ํ ๋ฐฉ๋ฒ๋ณด๋ค ๋ซ๋ค๊ณ ๋งํ๊ณ ์ถ์ต๋๋ค. ๋จ์ ์ ์์์ฆ์ ๋ก์ปฌ์ ์ ์ฅํด์ผ ํ๋ค๋ ๊ฒ์
๋๋ค. ์ด๊ฒ์ ๋๋ฌด ๋ฒ๊ฑฐ๋กญ์ง ์์์ผ ํฉ๋๋ค. ๋ํ ๋ณด์์์ ์ด์ ๋ก ๋๋ ๋์ฉ๋(์ต๋ 60,000์)์ด๋ผ๋ ์ฌ์ค ๋๋ฌธ์ ์ด๋ฌํ ์์์ฆ์ด ๋ฐฑ์๋๋ก ๊ฐ๋ ๊ฒ์ ์ํ์ง ์์ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๊ตฌ๋
ํ ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์ํ๊ฑฐ๋ ์ ์ฅ์น๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ๋ฉด ๋ค์์ ์ํํด์ผ ํฉ๋๋ค. ์ต์ ๊ตฌ๋งค ์์์ฆ์ ๋ฐ์ผ๋ ค๋ฉด ๋ก๊ทธ์ธํ๋ผ๋ ๋ฉ์์ง๊ฐ ํ์๋ฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก ํ์ธํ ์ฌ์ฉ์์๊ฒ๋ง ๋ฉ์์ง๋ฅผ ํ์ํ๋๋ก ๊ตฌ๋
์ํ๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ ์ฅํ ์ ์์ต๋๋ค.
@hyochan ์ ์ด ๋ฌธ์ ์ $20.00๋ฅผ ๊ธฐ๋ถํ์ต๋๋ค. IssueHunt์์ ํ์ธํ์ธ์.
@hyochan ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค ์๋ฃจ์ ์ ์๊ธ์ ์ง์ํ๊ณ ์์ต๋๊น? ์ฐ๋ฆฌ๋ ์ด ์ค๋ ๋์์ ๋ช ๊ฐ์ง๋ฅผ ์ ๊ณตํ์ผ๋ฉฐ ๋ด ์ต๊ทผ ์๊ฒฌ์ด ๊ฐ์ฅ ์ ์ ๋ฌธ์ ๋ก ๊ฐ์ฅ ๊ฐ๋ ฅํ ์๋ฃจ์ ์ ์ ๊ณตํ๋ค๊ณ ์๊ฐํฉ๋๋ค. README์ ๋ํ ํ๋์ ๊ฐ๊ฒฐํ PR๋ก ์ด๋ฌํ ์๋ฃจ์ ์ ์์งํ๊ธฐ ์ํด ๋๊ตฐ๊ฐ์๊ฒ ์๊ธ์ ์ง์ํ๊ณ ์์ต๋๊น? ์๋๋ฉด ์ฌ์ ํ ํด๊ฒฐ๋๊ธฐ๋ฅผ ์ํ๋ ์ค์ ์ฝ๋ ๋ฌธ์ ๊ฐ ์์ต๋๊น?
@kevinEsherick
README์ ๋ํ ํ๋์ ๊ฐ๊ฒฐํ PR๋ก ์ด๋ฌํ ์๋ฃจ์ ์ ์์งํ๊ธฐ ์ํด ๋๊ตฐ๊ฐ์๊ฒ ์๊ธ์ ์ง์ํ๊ณ ์์ต๋๊น?
์. ์ด๊ฒ์ ์ ๋์ ์ผ๋ก ๋ง์ต๋๋ค. ๋ํ issue hunt
๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ด๋ป๊ฒ ์๋ํ๋์ง ํ
์คํธํ๊ณ ์ถ์์ต๋๋ค. ๋ด ๋ค์ ๊ณํ์ ํ
์คํธ ์ผ์ด์ค๋ฅผ ๋ง๋๋ ๋ฐ ์๊ธ์ ์กฐ๋ฌํ๋ ๊ฒ์
๋๋ค.
@kevinEsherick ๋ง์ต๋๋ค. validateReceiptIos๋ฅผ ์ฌ์ฉํ ๋ก์ปฌ ์ ํจ์ฑ ๊ฒ์ฌ๋ ์ค์ ๋ก ์๋์ ์ฒซ ๋ฒ์งธ ํธ๋์ญ์ ID(redux ์ํ์ ์ ์ฅ๋จ)๋ง์ ์ฌ์ฉํ์ฌ ๊ตฌ๋ ์ ๋ํ ์ต์ ์ ๋ณด๋ฅผ ๋ฐํํฉ๋๋ค.
๋๋ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ด ์๋ฒ๋ฅผ ์ค์ ํ ํ์๊ฐ ์๊ณ ๊ตฌ๋ ์ด ํ์ฑํ๋์ด ์๋์ง ํ์ธํ๋ ๋์ iTunes ๋ก๊ทธ์ธ ํ์ ์ด ํ์๋์ง ์๋๋ก ํ ๊ฒ์ ๋๋ค.
@csumrell ๊ณผ ๋ด๊ฐ ๋ฐฐ์นํ ์ด ์ ํจ์ฑ ๊ฒ์ฌ ํ๋ฆ ์ฌ์ฉ์ ๊ณ ๋ คํ๋ ์ฌ๋๋ค์ ์ํ ์ฐธ๊ณ ์ฌํญ: ๊ฐ๋ฐ ์ค์ธ iTunes ๋ก๊ทธ์ธ ํ๋กฌํํธ๊ฐ ์ฒ์ ์์ํ ๋ ์ฌ์ ํ ํ์ ๋๋ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค. ์ด๊ฒ์ ํ๋ก๋์ ์์ ๋ฐ์ํ์ง ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ ์ํ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅด๊ธฐ๋ง ํ๋ฉด ๋ชจ๋ ๊ด์ฐฎ์ ๊ฒ์ ๋๋ค. ์ด ์์ ์ ์ํํ๋ ์ด์ ์ ๊ดํด์๋ ์๋ง๋ iOS๊ฐ IAP๊ฐ ์ฌ์ฉ ์ค์ด๊ฑฐ๋ ๊ฐ๋ฐ ์ค์ธ ๋ชจ๋ ๋งต์ ์ผ๋ถ์์ ํ์ธํ๋ฉด ์๋์ผ๋ก ๋ก๊ทธ์ธํ๋ผ๋ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. ํ์คํ์ง ์์ง๋ง ์๋๋ฐ์ค ํ ์คํธ์ ๊ธฐ๋ฅ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
์๋ ํ์ธ์, ์ต๊ทผ์ ์ด ๋ฌธ์ ์ ๋ํ ํ๋์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์์ต๋๊น? ์๋๋ฉด ์ฌ์ ํ ์ปค๋ฎค๋ํฐ์ ๊ด์ฌ์ด ํ์ํ๊ฐ์? ๋ ์ด์ ํ๋์ด ๋ฐ์ํ์ง ์์ผ๋ฉด ์ด ๋ฌธ์ ๊ฐ ์ข ๋ฃ๋ ์ ์์ต๋๋ค. ๋ํ ์ด ๋ฌธ์ ์ "ํ ๋ก ์ฉ" ๋๋ "์ข์ ์ฒซ ๋ฒ์งธ ๋ฌธ์ "๋ผ๋ ๋ ์ด๋ธ์ ๋ถ์ผ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ์ด์ด ๋๊ฒ ์ต๋๋ค. ๊ทํ์ ๊ธฐ์ฌ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
์ฅ๊ธฐ๊ฐ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์ด ๋ฌธ์ ๋ฅผ ์ข ๋ฃํฉ๋๋ค. ์ด ๋ฌธ์ ๊ฐ ์ต์ ๋ฆด๋ฆฌ์ค์ ์ฌ์ ํ ์กด์ฌํ๋ ๊ฒฝ์ฐ ์ธ์ ๋ ์ง ์ต์ ์ ๋ณด๋ก ์ ๋ฌธ์ ๋ฅผ ์์ฑํ์ญ์์ค.
์๋ง๋ ์ด ์ ์ฒด ํ๋ฆ์ ๋ฌธ์์์ ๋ช ํํ ํด์ผ ํฉ๋๊น?
ํนํ ์๋ ๊ฐฑ์ ๊ตฌ๋
์ ๊ฒฝ์ฐ? expires_date_ms
๊ตฌ๋
์ด ์์ง ํ์ฑํ๋์ด ์๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์๋์ง ์ฌ๋ถ๋ ์ ๊ท ์ด๋ฏผ์์๊ฒ ๋งค์ฐ ๋ถ๋ถ๋ช
ํฉ๋๋ค.
๋๋ ์ด๊ฒ์ ์ํ ๊ฐ์ฅ ์ข์ ์ฅ์๊ฐ ๋ณด๋ค ์์ ํ ์์ ์์ ์ผ ๊ฒ์ด๋ผ๊ณ ์ ์ํฉ๋๋ค.
์ฌ๋๋ค์ด ์ด๊ฒ์ ๊ด์ฌ์ ๊ฐ์ง๊น์? ์๊ฐ์ด ๋๋ค๋ฉด ์ด ์์ ์ ํด๋ ๋ ๊น์?
@alexpchin ๋ค, ํ์คํ ๊ฐ๋ฐ ์๊ฐ์ด ๋ง์ด ์ ์ฝ๋๊ณ ์ ์ฅ์ด ๊นจ๋ํด์ง๋๋ค:D
๋์ํ๋ค! #856์ ๊ด์ฌ์ด ์๋ ์ฌ๋์ด ์์ต๋๊น?
์๋ ,
@andrewzey ์ ๋ฐฉ๋ฒ์ ์ด์ ๊ฐ์๊ธฐ ๋ ์ด์ ๊ตฌ๋ ์ ๋ํ ์์์ฆ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ์ง ์๊ฒ ๋ ๋๊น์ง ํ๋ฅญํ๊ฒ ์๋ํ์ต๋๋ค. validateReceiptIos()๋ฅผ ํธ์ถํ ๋ iOS์์ JSON ๊ตฌ๋ฌธ ๋ถ์ ์ค๋ฅ๊ฐ ๋ค์ ๋ฐ์ํฉ๋๋ค. ๋๋ ์ด๊ฒ์ ๋ค๋ฅธ ์ฌ๋์ด ๋ง๋ ์ ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค ...? ์ด์ ์ดํ ๋ณ๊ฒฝ๋ ์ ์ผํ ๋ณ๊ฒฝ ์ฌํญ์ ๋ณ์๋ฅผ ์ ๊ฑฐํ๋ ๋ฐ ๋์์ด ๋๋๋ก ์ ๊ฑฐํ ITC์ ํ๋ก๋ชจ์ ์ฝ๋๊ฐ ์ถ๊ฐ๋ ๊ฒ์ ๋๋ค. ์์์ฆ์ด JSON ๊ตฌ๋ฌธ ๋ถ์์ ์คํจํด์ผ ํ๋ ์ด์ ๊ฐ ์์ต๋๊น? sortedAvailablePurchases์ ์ธ๋ฑ์ค 0์ ์๋ ์์์ฆ๋ฟ๋ง ์๋๋ผ ๋ฐํ๋ ๋ชจ๋ ์์์ฆ์ ๋ํด ์คํจํฉ๋๋ค. ์ฝ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก andrewzey์ ์์ ๋์ผํฉ๋๋ค. ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ validateReceiptIos ์ดํ์ ๋ชจ๋ ๊ฒ์ ์๋ตํ์ต๋๋ค.
RN 0.61.4, RNIap: 4.4.2 ๋ฐ iOS 13.3.1์ ์คํ ์ค์ ๋๋ค.
์ฐ๋ฆฌ๋ ์๋ํ์ต๋๋ค:
์๋๋ฐ์ค ๊ตฌ๋งค๋ฅผ ํ ๋ finishTransactionIOS๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ์ง ์์๋์ง ๊ถ๊ธํฉ๋๋ค.
์ ๋ง ์ด์ํ ์ ์ ์ด ์จ๋ผ์ธ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์์์ฆ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ ๋ ๋ชจ๋ ๊ฒ์ด ์ ์์ ์ผ๋ก ๋ณด์ด๊ณ ๋ชจ๋ ์์์ฆ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ณผ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
isSubscriptionActive = async () => {
const availablePurchases = await RNIap.getAvailablePurchases();
const sortedAvailablePurchases = availablePurchases.sort(
(a, b) => b.transactionDate - a.transactionDate
);
const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;
const isTestEnvironment = __DEV__;
try {
const decodedReceipt = await RNIap.validateReceiptIos(
{
'receipt-data': latestAvailableReceipt,
password: Config.IN_APP_PURCHASE_SECRET,
},
isTestEnvironment
);
console.log('response!', decodedReceipt)
} catch (error) {
console.warn('Error validating receipt', error) // JSON PARSE ERROR HERE
}
...
@andrewzey๊ฐ ๋ฐฐ์นํ ์ฝ๋์ ๊ดํ ์ง๋ฌธ์
๋๋ค. Date.now()
๊ฐ ํ์ฌ ์ฅ์น ์๊ฐ์ด ์๋๊ณ ์ฌ์ฉ์๊ฐ ์ด๋ฅผ ๋ณ๊ฒฝํ๊ณ ๋ฌด์ ํ ๊ตฌ๋
์ ๊ฐ์ง ์ ์์ต๋๊น? ๐ค
๋ํ ์ฑ ์์ฒด์์ ์์์ฆ์ ํ์ธํ๋ ๊ฒ์ด ์ข์ง ์์ต๋๊น?
@doteric ๊ทธ๋ค์ด ๋๋ดํ๋ค๊ณ ์ธ๊ธํ ๊ณณ์ ์๋ ค ์ฃผ์๊ฒ ์ต๋๊น? ์๋ฒ ์ธก ์๋ฆผ์ ์ค์ ํ ์ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ง๋ง ์ ๊ด์ ์์๋ ์๋ฒ ๋์ ํด๋ผ์ด์ธํธ์์ ์ด ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ํจ์ฌ ์ฌ์ ๋ณด์
๋๋ค.
Apple ๋๋ ๊ธฐํ ๊ฒฌ๊ณ ํ ๋ฐ์ ๋ค์ดํฐ๋ธ ์์ค์์ ์ฌ๋ฐ๋ฅธ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํด ๊ณ ๊ตฐ๋ถํฌํ๊ณ ์์ต๋๋ค.
@doteric yes Date.now()๋ ์ฅ์น ์๊ฐ์ด๋ฏ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฌ์ฉ์๊ฐ ์ด ์์ ์ ์ํํ ๊ฐ๋ฅ์ฑ์ ํฌ๋ฐํ๋ฉฐ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด๋ ๋์๋ ๊ตฌ๋ ์ด ๊ฐ๋ฅํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๊ฐ๋จํ ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฑ์ ์ด๊ธฐ ์ ์ ๋นํ๊ธฐ ๋ชจ๋๋ก ์ ํํ์ฌ ์ฑ์ด ๊ตฌ๋ ์ด ๋ง๋ฃ๋์์์ ์ธ์ํ์ง ๋ชปํ๋๋ก ํ ์ ์์ต๋๋ค. ๋ฌผ๋ก ๋ฐฐ์นํ ์ ์๋ ๋ค๋ฅธ ๋ณดํธ ๊ธฐ๋ฅ์ด ์์ง๋ง ์ ์์ ์ Date.now()๋ฅผ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ ์ธก์ด ํ์คํ ์๋ํ๋ค๋ ๊ฒ์ ๋๋ค. @captaincole ๋๋ ๋ฌธ์๋ฅผ ๊ฐ์ง๊ณ ์์ง ์์ง๋ง ํด๋ผ์ด์ธํธ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ๊ถ์ฅ๋์ง ์๋๋ค๋ ๊ฒ์ ์ฝ์์์ ํ์ธํ ์ ์์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ ๋ด๊ฐ ๋ฏฟ๋ Apple ๋ฌธ์์์ ์ฝ์์ต๋๋ค. ์ฆ, ํด๋ผ์ด์ธํธ ์ธก์์ ์์ ์ ์๋ฃํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
@kevinEsherick @captaincole
iOS์ ํด๋ผ์ด์ธํธ ์ธก ์์์ฆ ํ์ธ ์ ๋ณด:
์๋ ,
validateReceiptIos ๋ฐ latest_receipt_data(expires_date_ms๋ฅผ ์ค์ ๋ ์ง์ ๋น๊ต)๋ฅผ ์ฌ์ฉํ์ฌ ์ด ์ค๋ ๋์์ ๋ ผ์๋ ์ ๊ทผ ๋ฐฉ์ ์ค ํ๋๋ฅผ ์๋ํ์ต๋๋ค. Xcode์์ ๊ฐ๋ฐํ๋ ๋์ ํ๋ฅญํ๊ฒ ์๋ํ์ต๋๋ค. ๊ทธ๋ฌ๋ Testflight์์ ํ ์คํธํ์ ๋ ๋ ์ด์ ์๋ํ์ง ์์์ต๋๋ค. ๋๋ฒ๊น ์ด ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์ ํํ ๋ฌธ์ ๋ฅผ ์๋ณํ ์ ์์ผ๋ฉฐ ์์์ฆ ๋ฐ์ดํฐ๋ฅผ ์ป์ง ๋ชปํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋๊ตฌ๋ ์ง testflight์ ๋น์ทํ ๋ฌธ์ ๊ฐ ์์ต๋๊น?
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!
์๋ ,
validateReceiptIos ๋ฐ latest_receipt_data(expires_date_ms๋ฅผ ์ค์ ๋ ์ง์ ๋น๊ต)๋ฅผ ์ฌ์ฉํ์ฌ ์ด ์ค๋ ๋์์ ๋ ผ์๋ ์ ๊ทผ ๋ฐฉ์ ์ค ํ๋๋ฅผ ์๋ํ์ต๋๋ค. Xcode์์ ๊ฐ๋ฐํ๋ ๋์ ํ๋ฅญํ๊ฒ ์๋ํ์ต๋๋ค. ๊ทธ๋ฌ๋ Testflight์์ ํ ์คํธํ์ ๋ ๋ ์ด์ ์๋ํ์ง ์์์ต๋๋ค. ๋๋ฒ๊น ์ด ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์ ํํ ๋ฌธ์ ๋ฅผ ์๋ณํ ์ ์์ผ๋ฉฐ ์์์ฆ ๋ฐ์ดํฐ๋ฅผ ์ป์ง ๋ชปํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋๊ตฌ๋ ์ง testflight์ ๋น์ทํ ๋ฌธ์ ๊ฐ ์์ต๋๊น?
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!
+1
@asobralr @Somnus007 ์ ๊ฐ ํ๋ฆด ์๋ ์์ง๋ง ์ฌ์ฉ์๊ฐ testflight๋ฅผ ํตํด ๊ตฌ๋งคํ ์ ์๊ธฐ ๋๋ฌธ์ testflight๋ก IAP๋ฅผ ํ ์คํธํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. Apple์ ํ๋ก๋์ ๊ณผ ์ ์ฌํ ํ๊ฒฝ์์ ๊ตฌ๋งค๋ฅผ ํ ์คํธํ ์ ์๋ ์ข์ ๊ธฐํ๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค.
@asobralr @Somnus007 ์ ๊ฐ ํ๋ฆด ์๋ ์์ง๋ง ์ฌ์ฉ์๊ฐ testflight๋ฅผ ํตํด ๊ตฌ๋งคํ ์ ์๊ธฐ ๋๋ฌธ์ testflight๋ก IAP๋ฅผ ํ ์คํธํ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. Apple์ ํ๋ก๋์ ๊ณผ ์ ์ฌํ ํ๊ฒฝ์์ ๊ตฌ๋งค๋ฅผ ํ ์คํธํ ์ ์๋ ์ข์ ๊ธฐํ๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค.
์ณ์. ์๋๋ฐ์ค์์ ์คํจ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํ ์๋ ์์ต๋๋ค. ์ด๋ ๋ถ๋๋ฌ์ด ์ผ์ ๋๋ค. ๐
์๋ ํ์ธ์ @kevinEsherick๋ , ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค. ๋น์ ์ด ํ๋ฆด ์ ์์ต๋๋ค. ์ฌ์ฉ์๋ teslflight๋ฅผ ํตํด ๊ตฌ๋งคํ ์ ์์ต๋๋ค. testflight์์ ์ฌ์ฉ์๋ ์ค์ ์ฌ๊ณผ ๊ณ์ ๊ณผ ๋์ผํ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฐ์ง ์๋๋ฐ์ค ๊ณ์ ์ ๋ก๊ทธ์ธํด์ผ ํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ชจ๋ ๊ฒ์ด ์ ์๋ํฉ๋๋ค. BTW, getPurchaseHistory ๊ฐ ํ๋ก๋์ ํ๊ฒฝ์์ iTunes ๋ก๊ทธ์ธ ํ์ ์ ํธ๋ฆฌ๊ฑฐํฉ๋๊น?
ios 14๋ requestSubscription()์ ํธ์ถํ๊ธฐ ์ ์ getAvailablePurchases()๋ฅผ ํธ์ถํ ๋ ๋ฌธ์ ๊ฐ ์๋ค๋ ์ฌ์ค ๋๋ฌธ์ ์ด ์๋ฃจ์ ์ ์ค๋จํ ๊ฒ ๊ฐ์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ค์์ Android์ iOS ๋ชจ๋์์ ์๋ํ๋ฉฐ ์ต์ ์์์ฆ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์๋๋ก iOS์์ ์ ์ ํ๊ฒ ์ ๋ ฌํ๋ ๊ธฐ๋ฅ์ ๋๋ค.