Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
ethan
/
appframe
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit 0f7f20cd
authored
2026-07-17 17:59:35 +0800
by
ethanlamzs
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
优化
1 parent
1d8c2b03
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
28 additions
and
17 deletions
lib/services/subscription_service_ios.dart
pubspec.yaml
lib/services/subscription_service_ios.dart
View file @
0f7f20c
...
@@ -20,8 +20,6 @@ class SubscriptionService {
...
@@ -20,8 +20,6 @@ class SubscriptionService {
final
Map
<
String
,
Map
<
String
,
dynamic
>>
_pendingContexts
=
{};
final
Map
<
String
,
Map
<
String
,
dynamic
>>
_pendingContexts
=
{};
final
Map
<
String
,
String
>
_orderIdMap
=
{};
// key: productID, value: orderId
final
InAppPurchase
_iap
=
InAppPurchase
.
instance
;
final
InAppPurchase
_iap
=
InAppPurchase
.
instance
;
late
StreamSubscription
<
List
<
PurchaseDetails
>>
_purchaseUpdatedSubscription
;
late
StreamSubscription
<
List
<
PurchaseDetails
>>
_purchaseUpdatedSubscription
;
...
@@ -61,8 +59,6 @@ class SubscriptionService {
...
@@ -61,8 +59,6 @@ class SubscriptionService {
// 3. 从 App Store 获取产品信息
// 3. 从 App Store 获取产品信息
await
_fetchProducts
();
await
_fetchProducts
();
// 4. 处理待处理的交易(应用被杀掉时未完成交易)
//await _iap.restorePurchases(); // 订阅恢复也会触发 purchaseStream
}
}
...
@@ -86,11 +82,19 @@ class SubscriptionService {
...
@@ -86,11 +82,19 @@ class SubscriptionService {
}
}
Future
<
void
>
restoreSubscription
()
async
{
try
{
await
_iap
.
restorePurchases
();
}
catch
(
e
){
onError
?.
call
(
e
.
toString
());
}
}
// ---------- 购买订阅 ----------
// ---------- 购买订阅 ----------
Future
<
bool
>
buySubscription
(
ProductDetails
product
,
String
userId
,
String
tbxStuId
,
String
yWOrderId
)
async
{
Future
<
bool
>
buySubscription
(
ProductDetails
product
,
String
userId
,
String
tbxStuId
,
String
yWOrderId
)
async
{
_pendingContexts
[
product
.
id
]
=
{
'userId'
:
userId
,
'tbxStuId'
:
tbxStuId
,
"orderId"
:
yWOrderId
};
_pendingContexts
[
product
.
id
]
=
{
'userId'
:
userId
,
'tbxStuId'
:
tbxStuId
,
"orderId"
:
yWOrderId
};
_orderIdMap
[
product
.
id
]
=
yWOrderId
;
// 按产品 ID 存储
// 订阅必须使用 PurchaseParam 并设置购买类型为订阅
// 订阅必须使用 PurchaseParam 并设置购买类型为订阅
final
PurchaseParam
purchaseParam
=
PurchaseParam
(
final
PurchaseParam
purchaseParam
=
PurchaseParam
(
...
@@ -122,14 +126,14 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
...
@@ -122,14 +126,14 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
}
}
// 🔁 去重措施 1:根据原始交易 ID 去重,防止同一笔交易被重复处理
// 🔁 去重措施 1:根据原始交易 ID 去重,防止同一笔交易被重复处理
final
transactionId
=
purchaseDetails
.
verificationData
.
serverVerificationData
.
hashCode
.
toString
();
//
final transactionId = purchaseDetails.verificationData.serverVerificationData.hashCode.toString();
// 如果能获取到 purchaseID 更可靠,这里用 purchaseID 作为唯一标识
// 如果能获取到 purchaseID 更可靠,这里用 purchaseID 作为唯一标识
final
uniqueId
=
purchaseDetails
.
purchaseID
;
final
uniqueId
=
purchaseDetails
.
purchaseID
;
if
(
_processedTransactionIds
.
contains
(
uniqueId
))
{
if
(
_processedTransactionIds
.
contains
(
uniqueId
))
{
// 已经处理过,直接结束交易并跳过
// 已经处理过,直接结束交易并跳过
if
(
purchaseDetails
.
status
==
PurchaseStatus
.
purchased
||
if
(
purchaseDetails
.
status
==
PurchaseStatus
.
purchased
||
purchaseDetails
.
status
==
PurchaseStatus
.
restored
)
{
purchaseDetails
.
status
==
PurchaseStatus
.
restored
)
{
_iap
.
completePurchase
(
purchaseDetails
);
_iap
.
completePurchase
(
purchaseDetails
);
}
}
continue
;
continue
;
}
}
...
@@ -138,13 +142,13 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
...
@@ -138,13 +142,13 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
_processedTransactionIds
.
add
(
uniqueId
);
_processedTransactionIds
.
add
(
uniqueId
);
}
}
//var orderId = _orderIdMap.remove(purchaseDetails.productID); // 取出并删除
final
ctx
=
_pendingContexts
[
purchaseDetails
.
productID
]
;
final
ctx
=
_pendingContexts
[
purchaseDetails
.
productID
]
;
print
(
ctx
);
print
(
ctx
);
if
(
ctx
==
null
)
{
if
(
ctx
==
null
)
{
// 打印错误日志,防止崩溃
// 打印错误日志,防止崩溃
print
(
'错误:未找到 productID 对应的上下文缓存'
);
print
(
'错误:未找到 productID 对应的上下文缓存'
);
return
;
debugPrint
(
"No purchase context:
${purchaseDetails.productID}
"
);
continue
;
}
}
final
orderId
=
ctx
[
'orderId'
]
as
String
?;
final
orderId
=
ctx
[
'orderId'
]
as
String
?;
...
@@ -180,6 +184,9 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
...
@@ -180,6 +184,9 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
// 用户取消支付
// 用户取消支付
//_iap.completePurchase(purchaseDetails);
//_iap.completePurchase(purchaseDetails);
break
;
break
;
case
PurchaseStatus
.
pending
:
onStateChanged
?.
call
();
break
;
default
:
default
:
break
;
break
;
}
}
...
@@ -256,10 +263,14 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
...
@@ -256,10 +263,14 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
}
}
// ---------- 恢复成功处理 ----------
// ---------- 恢复成功处理 ----------
void
_handleRestoreSuccess
(
PurchaseDetails
detail
,
String
orderId
,
String
userId
)
{
Future
<
void
>
_handleRestoreSuccess
(
PurchaseDetails
detail
,
String
orderId
,
String
userId
)
async
{
// 注意:这里只是处理单个 restored,但最终 UI 刷新在 _onPurchaseUpdate 统一完成
// 注意:这里只是处理单个 restored,但最终 UI 刷新在 _onPurchaseUpdate 统一完成
_verifyReceipt
(
detail
,
orderId
??
''
,
userId
??
''
,
"purchased"
);
final
ok
=
await
_verifyReceipt
(
detail
,
orderId
??
''
,
userId
??
''
,
"purchased"
);
_iap
.
completePurchase
(
detail
);
if
(
ok
){
if
(
detail
.
pendingCompletePurchase
){
await
_iap
.
completePurchase
(
detail
);
}
}
}
}
// ---------- 错误处理 ----------
// ---------- 错误处理 ----------
...
@@ -276,9 +287,9 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
...
@@ -276,9 +287,9 @@ Future<bool> buySubscription(ProductDetails product, String userId , String tbxS
onError
?.
call
(
'支付已取消'
);
onError
?.
call
(
'支付已取消'
);
}
}
// 释放资源
// 释放资源
void
dispose
()
{
Future
<
void
>
dispose
()
async
{
_purchaseUpdatedSubscription
.
cancel
();
await
_purchaseUpdatedSubscription
.
cancel
();
}
}
}
\ No newline at end of file
\ No newline at end of file
}
pubspec.yaml
View file @
0f7f20c
name
:
appframe
name
:
appframe
description
:
"
app
frame
project."
description
:
"
app
frame
project."
publish_to
:
'
none'
publish_to
:
'
none'
version
:
1.1.
2
version
:
1.1.
3
environment
:
environment
:
sdk
:
"
>=3.5.0
<4.0.0"
sdk
:
"
>=3.5.0
<4.0.0"
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment