@nakamura-123/pages 1.1.9 → 1.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -171,14 +171,26 @@ var handlePurchase = function (productId) { return __awaiter(void 0, void 0, voi
171
171
  exports.handlePurchase = handlePurchase;
172
172
  // 21. 購入復元
173
173
  var restorePurchases = function (dispatch, isAlert) { return __awaiter(void 0, void 0, void 0, function () {
174
- var purchases, receipts, _i, purchases_1, purchase, receipt, finishError_1, itemError_1, storageError_1, hasWaitingPayment, error_1;
174
+ var connectionError_1, purchases, receipts, _i, purchases_1, purchase, receipt, finishError_1, itemError_1, dispatchError_1, storageError_1, hasWaitingPayment, error_1;
175
175
  return __generator(this, function (_a) {
176
176
  switch (_a.label) {
177
177
  case 0:
178
- _a.trys.push([0, 15, , 16]);
178
+ _a.trys.push([0, 23, , 24]);
179
179
  console.log("購入復元開始");
180
- return [4 /*yield*/, (0, expo_iap_1.getAvailablePurchases)()];
180
+ _a.label = 1;
181
181
  case 1:
182
+ _a.trys.push([1, 3, , 4]);
183
+ return [4 /*yield*/, (0, expo_iap_1.initConnection)()];
184
+ case 2:
185
+ _a.sent();
186
+ console.log("IAP接続完了");
187
+ return [3 /*break*/, 4];
188
+ case 3:
189
+ connectionError_1 = _a.sent();
190
+ console.warn("IAP接続は既に確立されています", connectionError_1);
191
+ return [3 /*break*/, 4];
192
+ case 4: return [4 /*yield*/, (0, expo_iap_1.getAvailablePurchases)()];
193
+ case 5:
182
194
  purchases = _a.sent();
183
195
  console.log("取得した購入アイテム: ", purchases);
184
196
  // Androidの場合、購入状態をログ出力
@@ -191,13 +203,13 @@ var restorePurchases = function (dispatch, isAlert) { return __awaiter(void 0, v
191
203
  }
192
204
  receipts = [];
193
205
  _i = 0, purchases_1 = purchases;
194
- _a.label = 2;
195
- case 2:
196
- if (!(_i < purchases_1.length)) return [3 /*break*/, 10];
206
+ _a.label = 6;
207
+ case 6:
208
+ if (!(_i < purchases_1.length)) return [3 /*break*/, 14];
197
209
  purchase = purchases_1[_i];
198
- _a.label = 3;
199
- case 3:
200
- _a.trys.push([3, 8, , 9]);
210
+ _a.label = 7;
211
+ case 7:
212
+ _a.trys.push([7, 12, , 13]);
201
213
  receipt = (0, ReceiptFnc_1.unifyReceipt)(purchase);
202
214
  if (receipt) {
203
215
  console.log("レシート情報: ", {
@@ -217,51 +229,60 @@ var restorePurchases = function (dispatch, isAlert) { return __awaiter(void 0, v
217
229
  else {
218
230
  console.warn("レシートの統一に失敗(スキップします): ", purchase);
219
231
  }
220
- if (!checkIsAcknowledgedAndroid(purchase)) return [3 /*break*/, 7];
221
- _a.label = 4;
222
- case 4:
223
- _a.trys.push([4, 6, , 7]);
232
+ if (!checkIsAcknowledgedAndroid(purchase)) return [3 /*break*/, 11];
233
+ _a.label = 8;
234
+ case 8:
235
+ _a.trys.push([8, 10, , 11]);
224
236
  return [4 /*yield*/, (0, expo_iap_1.finishTransaction)({ purchase: purchase, isConsumable: false })];
225
- case 5:
237
+ case 9:
226
238
  _a.sent();
227
239
  console.log("トランザクション完了: ", purchase.productId);
228
- return [3 /*break*/, 7];
229
- case 6:
240
+ return [3 /*break*/, 11];
241
+ case 10:
230
242
  finishError_1 = _a.sent();
231
243
  console.error("トランザクション完了エラー(継続します): ", finishError_1);
232
- return [3 /*break*/, 7];
233
- case 7: return [3 /*break*/, 9];
234
- case 8:
244
+ return [3 /*break*/, 11];
245
+ case 11: return [3 /*break*/, 13];
246
+ case 12:
235
247
  itemError_1 = _a.sent();
236
248
  console.error("購入アイテムの処理エラー(次のアイテムへ継続): ", itemError_1);
237
249
  console.error("問題のあるアイテム: ", purchase);
238
- return [3 /*break*/, 9];
239
- case 9:
250
+ return [3 /*break*/, 13];
251
+ case 13:
240
252
  _i++;
241
- return [3 /*break*/, 2];
242
- case 10:
243
- // 購入アイテムがない場合はAllFreeの状態を更新
244
- if (receipts.length === 0) {
245
- try {
246
- dispatch((0, exports.updateAllFreeState)(null));
247
- }
248
- catch (dispatchError) {
249
- console.error("状態更新エラー(null時): ", dispatchError);
250
- }
251
- }
252
- if (!(receipts.length > 0)) return [3 /*break*/, 14];
253
- _a.label = 11;
254
- case 11:
255
- _a.trys.push([11, 13, , 14]);
253
+ return [3 /*break*/, 6];
254
+ case 14:
255
+ if (!(receipts.length === 0)) return [3 /*break*/, 18];
256
+ console.warn('購入アイテムが見つかりませんでした。状態を"none"に更新します(返金済み等)');
257
+ _a.label = 15;
258
+ case 15:
259
+ _a.trys.push([15, 17, , 18]);
260
+ dispatch((0, exports.updateAllFreeState)(null));
261
+ // 🔧 重要:Keychainも空にする(返金時に古いデータが残らないように)
262
+ return [4 /*yield*/, stores_1.coinStorage.replacePurchasedItems([])];
263
+ case 16:
264
+ // 🔧 重要:Keychainも空にする(返金時に古いデータが残らないように)
265
+ _a.sent();
266
+ console.log("Keychainの購入データを削除しました");
267
+ return [3 /*break*/, 18];
268
+ case 17:
269
+ dispatchError_1 = _a.sent();
270
+ console.error("状態更新エラー(null時): ", dispatchError_1);
271
+ return [3 /*break*/, 18];
272
+ case 18:
273
+ if (!(receipts.length > 0)) return [3 /*break*/, 22];
274
+ _a.label = 19;
275
+ case 19:
276
+ _a.trys.push([19, 21, , 22]);
256
277
  return [4 /*yield*/, stores_1.coinStorage.replacePurchasedItems(receipts)];
257
- case 12:
278
+ case 20:
258
279
  _a.sent();
259
- return [3 /*break*/, 14];
260
- case 13:
280
+ return [3 /*break*/, 22];
281
+ case 21:
261
282
  storageError_1 = _a.sent();
262
283
  console.error("ストレージ保存エラー: ", storageError_1);
263
- return [3 /*break*/, 14];
264
- case 14:
284
+ return [3 /*break*/, 22];
285
+ case 22:
265
286
  console.log("購入復元完了: ", receipts.length, "件");
266
287
  // アラート表示(支払い待ち状態を考慮)
267
288
  if (isAlert) {
@@ -285,7 +306,7 @@ var restorePurchases = function (dispatch, isAlert) { return __awaiter(void 0, v
285
306
  }
286
307
  }
287
308
  return [2 /*return*/, receipts]; // 復元アイテムがあればpurchasesを返す
288
- case 15:
309
+ case 23:
289
310
  error_1 = _a.sent();
290
311
  console.error("Restore Error: ", error_1);
291
312
  console.error("エラーの詳細: ", error_1 instanceof Error ? error_1.message : String(error_1));
@@ -293,7 +314,7 @@ var restorePurchases = function (dispatch, isAlert) { return __awaiter(void 0, v
293
314
  isAlert &&
294
315
  alert("購入アイテムの復元に失敗しました。しばらく時間を置いた後、もう一度実行してみてください。もしそれでも購入できない場合は「よくある質問」をご確認いただくか、必要に応じて「お問い合わせフォーム」からご連絡ください。");
295
316
  return [2 /*return*/, null]; // エラーが発生した場合もnullを返す
296
- case 16: return [2 /*return*/];
317
+ case 24: return [2 /*return*/];
297
318
  }
298
319
  });
299
320
  }); };
@@ -9,17 +9,20 @@ var unifyReceipt = function (receipt) {
9
9
  console.warn("無効なレシートデータ: productIdが不足しています", receipt);
10
10
  return null;
11
11
  }
12
- if (!receipt.transactionId) {
13
- console.warn("無効なレシートデータ: transactionIdが不足しています", receipt);
14
- return null;
15
- }
12
+ // expo-iap 2.9.7では transactionId の代わりに id を使用
13
+ // Androidで支払い待ち状態の場合、transactionIdがnullになることがあるため、purchaseTokenをフォールバックとして使用
14
+ var transactionId = receipt.transactionId || receipt.id;
16
15
  if (receipt.platform === "android") {
17
16
  if (!receipt.purchaseToken) {
18
17
  console.warn("無効なAndroidレシート: purchaseTokenが不足しています");
19
18
  return null;
20
19
  }
20
+ // transactionIdがnullの場合はpurchaseTokenを使用(コンビニ支払いなど)
21
+ if (!transactionId) {
22
+ transactionId = receipt.purchaseToken;
23
+ }
21
24
  return {
22
- transactionId: receipt.transactionId,
25
+ transactionId: transactionId,
23
26
  productId: receipt.productId,
24
27
  transactionDate: Number(receipt.transactionDate) || Date.now(),
25
28
  receipt: receipt.purchaseToken,
@@ -27,15 +30,20 @@ var unifyReceipt = function (receipt) {
27
30
  };
28
31
  }
29
32
  else if (receipt.platform === "ios") {
30
- if (!receipt.transactionReceipt) {
31
- console.warn("無効なiOSレシート: transactionReceiptが不足しています");
33
+ if (!receipt.transactionReceipt && !receipt.purchaseToken) {
34
+ console.warn("無効なiOSレシート: transactionReceipt/purchaseTokenが不足しています");
35
+ return null;
36
+ }
37
+ // iOSの場合もtransactionIdが必須
38
+ if (!transactionId) {
39
+ console.warn("無効なiOSレシート: transactionIdが不足しています", receipt);
32
40
  return null;
33
41
  }
34
42
  return {
35
- transactionId: receipt.transactionId,
43
+ transactionId: transactionId,
36
44
  productId: receipt.productId,
37
45
  transactionDate: Number(receipt.transactionDate) || Date.now(),
38
- receipt: receipt.transactionReceipt,
46
+ receipt: receipt.transactionReceipt || receipt.purchaseToken || "",
39
47
  isPaid: true, // iOSでは即時完了
40
48
  };
41
49
  }
@@ -27,11 +27,11 @@ exports.faqEnDatas = [
27
27
  },
28
28
  {
29
29
  que: "購入手続きが失敗する",
30
- ans: " 購入手続きが失敗となる場合は、以下のいずれかの可能性が考えられます。 \n 1.すでに購入が済んでいる場合があります。問題が画面や単元別、試験別画面をご確認ください。 \n2.アプリを削除したり、iPhoneを替えたりした場合は、購入状態をアプリが判別できません。この場合は、アップグレードページの「以前購入した方はこちらから復元」ボタンをタップしてください。 \n3.通信環境やアカウントの状態等により、購入が正しく行えない場合があります。 お手数ですが、画面の表示動作についてご連絡いただけるでしょうか。 連絡の際は、下記のアドレスへメールいただければ幸いです。 \ndk2drill@gmail.com ",
30
+ ans: " 購入手続きが失敗となる場合は、以下のいずれかの可能性が考えられます。 \n 1.すでに購入が済んでいる場合があります。問題が画面や単元別、試験別画面をご確認ください。 \n2.アプリを削除したり、iPhoneを替えたりした場合は、購入状態をアプリが判別できません。この場合は、アップグレードページの「以前購入した方はこちらから復元」ボタンをタップしてください。 \n3.通信環境やアカウントの状態等により、購入が正しく行えない場合があります。 お手数ですが、画面の表示動作についてご連絡いただけるでしょうか。 連絡の際は、下記のアドレスへメールいただければ幸いです。 \nsupport@drill-notes.com ",
31
31
  },
32
32
  {
33
33
  que: "コンビニ支払いをしたが、有料版を利用できません。",
34
- ans: " Androidでのコンビニ支払いをご利用の場合、決済完了後に「以前購入した方はこちらから復元」をタップする必要があります。\n また、時間が経ってもサービスが利用できない場合には、大変恐れ入りますが、以下のメールアドレスまでご連絡の上、クレジットカード等の他の支払い方法で再度お手続きいただけますようお願いいたします。\ndk2drill@gmail.com ",
34
+ ans: " Androidでのコンビニ支払いをご利用の場合、決済完了後に「以前購入した方はこちらから復元」をタップする必要があります。\n また、時間が経ってもサービスが利用できない場合には、大変恐れ入りますが、以下のメールアドレスまでご連絡の上、クレジットカード等の他の支払い方法で再度お手続きいただけますようお願いいたします。\nsupport@drill-notes.com ",
35
35
  },
36
36
  {
37
37
  que: "領収書を発行することはできますか",
@@ -27,11 +27,11 @@ exports.faqJaDatas = [
27
27
  },
28
28
  {
29
29
  que: "購入手続きが失敗する",
30
- ans: " 購入手続きが失敗となる場合は、以下のいずれかの可能性が考えられます。 \n 1.すでに購入が済んでいる場合があります。問題が画面や単元別、試験別画面をご確認ください。 \n2.アプリを削除したり、iPhoneを替えたりした場合は、購入状態をアプリが判別できません。この場合は、アップグレードページの「以前購入した方はこちらから復元」ボタンをタップしてください。 \n3.通信環境やアカウントの状態等により、購入が正しく行えない場合があります。 お手数ですが、画面の表示動作についてご連絡いただけるでしょうか。 連絡の際は、下記のアドレスへメールいただければ幸いです。 \ndk2drill@gmail.com ",
30
+ ans: " 購入手続きが失敗となる場合は、以下のいずれかの可能性が考えられます。 \n 1.すでに購入が済んでいる場合があります。問題が画面や単元別、試験別画面をご確認ください。 \n2.アプリを削除したり、iPhoneを替えたりした場合は、購入状態をアプリが判別できません。この場合は、アップグレードページの「以前購入した方はこちらから復元」ボタンをタップしてください。 \n3.通信環境やアカウントの状態等により、購入が正しく行えない場合があります。 お手数ですが、画面の表示動作についてご連絡いただけるでしょうか。 連絡の際は、下記のアドレスへメールいただければ幸いです。 \nsupport@drill-notes.com ",
31
31
  },
32
32
  {
33
33
  que: "コンビニ支払いをしたが、有料版を利用できません。",
34
- ans: " Androidでのコンビニ支払いをご利用の場合、決済完了後に「以前購入した方はこちらから復元」をタップする必要があります。\n また、時間が経ってもサービスが利用できない場合には、大変恐れ入りますが、以下のメールアドレスまでご連絡の上、クレジットカード等の他の支払い方法で再度お手続きいただけますようお願いいたします。\ndk2drill@gmail.com ",
34
+ ans: " Androidでのコンビニ支払いをご利用の場合、決済完了後に「以前購入した方はこちらから復元」をタップする必要があります。\n また、時間が経ってもサービスが利用できない場合には、大変恐れ入りますが、以下のメールアドレスまでご連絡の上、クレジットカード等の他の支払い方法で再度お手続きいただけますようお願いいたします。\nsupport@drill-notes.com ",
35
35
  },
36
36
  {
37
37
  que: "領収書を発行することはできますか",
@@ -65,8 +65,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
65
65
  var react_1 = __importStar(require("react"));
66
66
  var react_redux_1 = require("react-redux");
67
67
  var stores_1 = require("@nakamura-123/stores");
68
- // import RNIap, { endConnection } from "react-native-iap";
69
- var expo_iap_1 = require("expo-iap");
70
68
  var CoinPageComponent_1 = __importDefault(require("../component/Coin/CoinPageComponent"));
71
69
  var CoinFnc_1 = require("../component/Coin/CoinFnc");
72
70
  var ReceiptFnc_1 = require("../component/Coin/ReceiptFnc");
@@ -83,10 +81,11 @@ var CoinPage = function (_a) {
83
81
  var items = allFreeId ? [allFreeId] : [];
84
82
  (0, react_1.useEffect)(function () {
85
83
  (0, CoinFnc_1.initializeIAP)(items, setProducts, setLoading);
86
- // アンマウント時に接続を終了
87
- return function () {
88
- (0, expo_iap_1.endConnection)();
89
- };
84
+ // 🔧 修正4: endConnection()を削除(接続を維持)
85
+ // アプリ終了時に自動的に切断されるため、明示的な切断は不要
86
+ // return () => {
87
+ // endConnection();
88
+ // };
90
89
  }, []);
91
90
  // 02.購入時の処理の実行
92
91
  var handlePurchaseItem = function (productId) { return __awaiter(void 0, void 0, void 0, function () {
@@ -144,6 +143,7 @@ var CoinPage = function (_a) {
144
143
  switch (_a.label) {
145
144
  case 0:
146
145
  setLoading(true); // 処理開始
146
+ receipts = null;
147
147
  _a.label = 1;
148
148
  case 1:
149
149
  _a.trys.push([1, 3, 4, 5]);
@@ -167,7 +167,22 @@ var CoinPage = function (_a) {
167
167
  console.error("エラーの詳細: ", error_2 instanceof Error ? error_2.message : String(error_2));
168
168
  return [3 /*break*/, 5];
169
169
  case 4:
170
- dispatch(stores_1.settingStorage.saveSetting());
170
+ // 🔧 修正5(再修正): エラー時のみ保存しない、正常完了時は常に保存
171
+ // receipts === null → 通信エラー等(状態を保持)
172
+ // receipts === [] → 購入なし/返金済み("none"に更新して保存)
173
+ // receipts !== null → 正常に取得完了(常に保存)
174
+ if (receipts !== null) {
175
+ dispatch(stores_1.settingStorage.saveSetting());
176
+ if (receipts.length > 0) {
177
+ console.log("\u5FA9\u5143\u6210\u529F\uFF1A".concat(receipts.length, "\u4EF6\u306E\u8CFC\u5165\u3092\u78BA\u8A8D\u3057\u3001\u8A2D\u5B9A\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F"));
178
+ }
179
+ else {
180
+ console.log('復元完了:購入アイテムなし(返金済み等)。状態を"none"に更新しました');
181
+ }
182
+ }
183
+ else {
184
+ console.log("復元エラー:通信失敗等のため設定を保存しませんでした(既存状態を保持)");
185
+ }
171
186
  setLoading(false); // 処理終了
172
187
  return [7 /*endfinally*/];
173
188
  case 5: return [2 /*return*/];
@@ -76,6 +76,7 @@ var WaitingPayBanner_1 = __importDefault(require("../component/Coin/WaitingPayBa
76
76
  var oldStorageFnc_1 = require("../functions/oldStorageFnc");
77
77
  var OpeningMsg_1 = __importDefault(require("../component/Home/OpeningMsg"));
78
78
  var TransBtn_1 = __importDefault(require("../component/SettingBtns/TransBtn"));
79
+ var CoinFnc_1 = require("../component/Coin/CoinFnc");
79
80
  var MenuRectangle = function (_a) {
80
81
  var menu = _a.menu, navigation = _a.navigation;
81
82
  var title = menu.title, note = menu.note, icon = menu.icon, color = menu.color, link = menu.link;
@@ -123,6 +124,39 @@ var HomePage = function (_a) {
123
124
  }); };
124
125
  fetchOldData();
125
126
  }, [showLoadOldData, settingAsyncLoaded, language]);
127
+ // 🔧 修正6: アプリ起動時にKeychainから購入情報を復元
128
+ (0, react_1.useEffect)(function () {
129
+ if (!settingAsyncLoaded)
130
+ return;
131
+ var restorePurchaseState = function () { return __awaiter(void 0, void 0, void 0, function () {
132
+ var receipts, error_1;
133
+ return __generator(this, function (_a) {
134
+ switch (_a.label) {
135
+ case 0:
136
+ _a.trys.push([0, 2, , 3]);
137
+ return [4 /*yield*/, stores_1.coinStorage.loadPurchasedItems()];
138
+ case 1:
139
+ receipts = _a.sent();
140
+ if (receipts && receipts.length > 0) {
141
+ console.log("HomePage\u8D77\u52D5\u6642: ".concat(receipts.length, "\u4EF6\u306E\u8CFC\u5165\u60C5\u5831\u3092\u5FA9\u5143\u3057\u307E\u3059"));
142
+ receipts.forEach(function (receipt) {
143
+ dispatch((0, CoinFnc_1.updateAllFreeState)(receipt));
144
+ });
145
+ }
146
+ else {
147
+ console.log("HomePage起動時: 購入情報が見つかりませんでした");
148
+ }
149
+ return [3 /*break*/, 3];
150
+ case 2:
151
+ error_1 = _a.sent();
152
+ console.error("購入情報の読み込みに失敗しました:", error_1);
153
+ return [3 /*break*/, 3];
154
+ case 3: return [2 /*return*/];
155
+ }
156
+ });
157
+ }); };
158
+ restorePurchaseState();
159
+ }, [settingAsyncLoaded]);
126
160
  // これはデバッグ用です。
127
161
  (0, react_1.useEffect)(function () {
128
162
  if (__DEV__)