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 45d44847
authored
2026-07-09 21:20:08 +0800
by
ethanlamzs
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
调试订单
1 parent
01c75d92
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
37 additions
and
108 deletions
build_ios.sh
clean_ios.sh
ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
ios/Runner/LocalIAP.storekit
lib/data/repositories/message/xe_create_order_handler.dart
lib/data/repositories/user_auth_repository.dart
lib/services/dispatcher.dart
lib/services/subscription_service_ios.dart
build_ios.sh
View file @
45d4484
...
...
@@ -60,6 +60,12 @@ if [ ! -z "$ot" ]; then
if
[
"
$ot
"
==
'11'
]
;
then
flutter run --dart-define
=
env
=
$env
--dart-define
=
version
=
$_main_ver$_ver
-d 00008030-001C75810E42402E
fi
if
[
"
$ot
"
==
'sim'
]
;
then
flutter run --debug --dart-define
=
env
=
$env
--dart-define
=
version
=
$_main_ver$_ver
-d 89482737-FAA1-4145-BB2D-4B1B122B5B37
fi
else
echo
'build else '
fi
...
...
clean_ios.sh
View file @
45d4484
...
...
@@ -20,7 +20,7 @@ flutter pub get
#pod deintegrate
# 4. 清理 CocoaPods 本地缓存 (这一步很重要,ffmpeg 包很大,容易缓存损坏)
pod cache clean --all
#
pod cache clean --all
# 5. 重新安装 Pods 并更新仓库索引
# 注意:这一步可能比较慢,因为 ffmpeg 库非常大(几百MB),请保持网络通畅
...
...
ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
View file @
45d4484
...
...
@@ -73,9 +73,6 @@
ReferencedContainer =
"container:Runner.xcodeproj"
>
</BuildableReference>
</BuildableProductRunnable>
<StoreKitConfigurationFileReference
identifier =
"../Runner/LocalIAP.storekit"
>
</StoreKitConfigurationFileReference>
</LaunchAction>
<ProfileAction
buildConfiguration =
"Profile"
...
...
ios/Runner/LocalIAP.storekit
deleted
100644 → 0
View file @
01c75d9
{
"appPolicies" : {
"eula" : "",
"policies" : [
{
"locale" : "en_US",
"policyText" : "",
"policyURL" : ""
}
]
},
"identifier" : "8ADF1697",
"nonRenewingSubscriptions" : [
{
"displayPrice" : "8.0",
"familyShareable" : false,
"internalID" : "9F78CD7A",
"localizations" : [
{
"description" : "vipm1",
"displayName" : "vipm1",
"locale" : "zh_Hans"
}
],
"productID" : "cn.banxe.appframe.membership.1m",
"referenceName" : "month1",
"type" : "NonRenewingSubscription"
},
{
"displayPrice" : "16.0",
"familyShareable" : false,
"internalID" : "119703EA",
"localizations" : [
{
"description" : "vipm2",
"displayName" : "vipm2",
"locale" : "zh_Hans"
}
],
"productID" : "cn.banxe.appframe.membership.2m",
"referenceName" : "month2",
"type" : "NonRenewingSubscription"
},
{
"displayPrice" : "22.0",
"familyShareable" : false,
"internalID" : "4768E67B",
"localizations" : [
{
"description" : "vipm3",
"displayName" : "vipm3",
"locale" : "zh_Hans"
}
],
"productID" : "cn.banxe.appframe.membership.3m",
"referenceName" : "month3",
"type" : "NonRenewingSubscription"
}
],
"products" : [
],
"settings" : {
"_askToBuyEnabled" : false,
"_billingGracePeriodEnabled" : false,
"_billingIssuesEnabled" : false,
"_disableDialogs" : false,
"_failTransactionsEnabled" : false,
"_locale" : "en_US",
"_renewalBillingIssuesEnabled" : false,
"_storefront" : "USA",
"_storeKitErrors" : [
],
"_timeRate" : 0
},
"subscriptionGroups" : [
],
"version" : {
"major" : 4,
"minor" : 0
}
}
lib/data/repositories/message/xe_create_order_handler.dart
View file @
45d4484
...
...
@@ -31,7 +31,7 @@ class XeCreateOrderHandler extends MessageHandler {
@override
Future
<
dynamic
>
handleMessage
(
params
)
async
{
print
(
"
handleMessage "
+
params
);
print
(
"
############## handleMessage #############"
);
// 从 params 中提取支付参数
final
String
chargeCode
=
params
[
'chargeCode'
]
as
String
?
??
''
;
final
int
durationType
=
params
[
'durationType'
]
as
int
?
??
0
;
...
...
@@ -64,7 +64,7 @@ class XeCreateOrderHandler extends MessageHandler {
await
_wx_pay_proc_
(
userCode
,
tbxStuId
,
chargeCode
,
deviceType
,
phone
,
stuId
,
ext
,
duration
,
durationType
,
totalFee
,
renew
,
useCoin
);
}
else
if
(
deviceType
==
'ios'
){
// 暂时不支持使用学币扣减
await
_ios_pay_proc_
(
userCode
,
tbxStuId
,
chargeCode
,
deviceType
,
phone
,
stuId
,
ext
,
duration
,
durationType
,
totalFee
,
renew
,
0
);
await
_ios_pay_proc_
(
userCode
,
tbxStuId
,
chargeCode
,
deviceType
,
phone
,
stuId
,
ext
,
duration
,
durationType
,
totalFee
,
renew
,
false
);
}
}
...
...
@@ -77,7 +77,6 @@ class XeCreateOrderHandler extends MessageHandler {
throw
Exception
(
'设备上未安装微信App,不支持微信支付'
);
}
var
result
=
await
_userAuthRepository
.
createOrder
(
userCode
,
tbxStuId
,
chargeCode
,
duration
,
durationType
,
totalFee
,
renew
,
phone
,
stuId
,
ext
,
useCoin
?
1
:
0
,
deviceType
);
if
(
result
==
null
)
{
...
...
@@ -202,28 +201,31 @@ class XeCreateOrderHandler extends MessageHandler {
// 执行ios的微信支付
Future
<
dynamic
>
_ios_pay_proc_
(
String
userCode
,
tbxStuId
,
chargeCode
,
deviceType
,
phone
,
stuId
,
ext
,
int
duration
,
durationType
,
totalFee
,
bool
renew
,
useCoin
)
async
{
print
(
"[debug]. _ios_pay_proc_ 11 "
);
// 暂时用固定的价格
var
result
=
await
_userAuthRepository
.
createOrder
(
userCode
,
tbxStuId
,
chargeCode
,
duration
,
durationType
,
totalFee
,
renew
,
phone
,
stuId
,
ext
,
useCoin
?
1
:
0
,
deviceType
);
print
(
"[debug]. _ios_pay_proc_ 1 "
);
print
(
"[debug]. _ios_pay_proc_ 12 "
);
print
(
result
);
// map[nonceStr:qNfHK6a95jjJkwzDkh0h3fhfUVuS0jZ9 paySign: timeStamp:1783497438 wxTradeNo:to1281644408384671744]
var
data
=
result
[
'data'
]
as
Map
<
String
,
dynamic
>?;
if
(
data
==
null
)
{
throw
Exception
(
'支付参数获取失败'
);
}
print
(
"[debug]. _ios_pay_proc_
2
"
);
print
(
"[debug]. _ios_pay_proc_
13
"
);
// 3. 从后端响应中提取预支付ID
final
prepayId
=
data
[
'prepayId
'
]
as
String
?;
if
(
prepayId
==
null
||
prepayId
.
isEmpty
)
{
throw
Exception
(
'
预支付订单ID获取
失败'
);
final
wxTradeNo
=
data
[
'wxTradeNo
'
]
as
String
?;
if
(
wxTradeNo
==
null
||
wxTradeNo
.
isEmpty
)
{
throw
Exception
(
'
订单生成
失败'
);
}
// 4. 从后端响应中提取支付参数(nonceStr、timestamp、paySign 由后端生成)
final
timestamp
=
data
[
'timeStamp'
]
as
int
;
final
wxTradeNo
=
data
[
'wxTradeNo'
]
as
String
;
print
(
"[debug]. _ios_pay_proc_ 3 "
);
debugPrint
(
'_ios_pay_proc_ => prepayId:
$prepayId
'
);
debugPrint
(
'_ios_pay_proc_ => timestamp:
$timestamp
'
);
debugPrint
(
'_ios_pay_proc_ => wxTradeNo:
$wxTradeNo
'
);
...
...
@@ -235,9 +237,14 @@ class XeCreateOrderHandler extends MessageHandler {
await
_subService
.
initialize
();
// 为了调试,先模拟
final
product
=
_subService
.
products
[
0
];
_subService
.
buySubscription
(
product
,
userCode
,
tbxStuId
,
wxTradeNo
);
var
product
;
for
(
var
p
in
_subService
.
products
)
{
debugPrint
(
'x1=====> 产品ID:
${p.id}
, 标题:
${p.title}
, 价格:
${p.price}
'
);
}
product
=
_subService
.
products
[
0
];
_subService
.
buySubscription
(
product
,
userCode
,
tbxStuId
,
wxTradeNo
);
}
...
...
lib/data/repositories/user_auth_repository.dart
View file @
45d4484
...
...
@@ -163,8 +163,10 @@ class UserAuthRepository {
}
// 检查ios的订单是否已经订阅
Future
<
dynamic
>
orderCheck
(
String
userId
,
String
receipt
,
String
orderid
,
String
platform
)
async
{
Future
<
dynamic
>
orderCheck
(
String
userId
,
String
receipt
,
String
orderid
,
String
platform
,
int
isSandbox
)
async
{
try
{
debugPrint
(
'收据长度:
${receipt.length}
'
);
debugPrint
(
'收据前100字符:
${receipt.substring(0, receipt.length > 100 ? 100 : receipt.length)}
'
);
Response
resp
=
await
_appService
.
post
(
'/api/v1/comm/user/ordercheck'
,
{
...
...
@@ -172,6 +174,7 @@ class UserAuthRepository {
"receipt"
:
receipt
,
"orderid"
:
orderid
,
"platform"
:
platform
,
"isSandbox"
:
isSandbox
,
},
);
return
resp
.
statusCode
==
HttpStatus
.
ok
?
resp
.
data
:
null
;
...
...
lib/services/dispatcher.dart
View file @
45d4484
...
...
@@ -36,7 +36,6 @@ class MessageDispatcher {
Future
<
void
>
dispatch
(
String
message
,
Function
callback
,
{
WebCubit
?
webCubit
})
async
{
final
Map
<
String
,
dynamic
>
data
=
json
.
decode
(
message
);
H5Message
h5Message
=
H5Message
.
fromJson
(
data
);
print
(
data
);
var
handler
=
_handlers
[
h5Message
.
cmd
];
if
(
handler
==
null
)
{
try
{
...
...
lib/services/subscription_service_ios.dart
View file @
45d4484
// subscription_service.dart
import
'dart:async'
;
import
'package:in_app_purchase/in_app_purchase.dart'
;
import
'package:http/http.dart'
as
http
;
import
'package:flutter/widgets.dart'
;
import
'package:appframe/data/repositories/user_auth_repository.dart'
;
import
'package:appframe/config/locator.dart'
;
...
...
@@ -12,8 +11,9 @@ class SubscriptionService {
// App Store Connect 中配置的订阅产品 ID(组内唯一)
// 例如月度、年度两种方案
static
const
String
monthlySubId_1
=
'cn.banxe.appframe.membership.1m'
;
static
const
String
monthlySubId_2
=
'cn.banxe.appframe.membership.2m'
;
static
const
String
monthlySubId_3
=
'cn.banxe.appframe.membership.3m'
;
static
const
String
monthlySubId_6
=
'cn.banxe.appframe.membership.6m'
;
static
const
String
monthlySubId_12
=
'cn.banxe.appframe.membership.12m'
;
// 纯粹的数据容器,不继承任何类
final
Map
<
String
,
Map
<
String
,
dynamic
>>
_pendingContexts
=
{};
...
...
@@ -54,7 +54,7 @@ class SubscriptionService {
// ---------- 获取产品信息 ----------
Future
<
void
>
_fetchProducts
()
async
{
const
Set
<
String
>
ids
=
{
monthlySubId_1
,
monthlySubId_
2
,
monthlySubId_3
};
const
Set
<
String
>
ids
=
{
monthlySubId_1
,
monthlySubId_
3
,
monthlySubId_6
,
monthlySubId_12
};
final
ProductDetailsResponse
response
=
await
_iap
.
queryProductDetails
(
ids
);
...
...
@@ -114,6 +114,7 @@ class SubscriptionService {
final
orderId
=
_orderIdMap
.
remove
(
purchaseDetails
.
productID
);
// 取出并删除
final
ctx
=
_pendingContexts
[
purchaseDetails
.
productID
];
print
(
ctx
);
// 1. 验证收据(必须!)
_verifyReceipt
(
purchaseDetails
,
orderId
??
''
);
...
...
@@ -147,7 +148,7 @@ class SubscriptionService {
debugPrint
(
'无收据数据'
);
return
;
}
debugPrint
(
"[info] _verifyReceipt is start "
+
purchaseDetails
.
productID
+
" : "
+
purchaseDetails
.
toString
()
);
debugPrint
(
"[info] _verifyReceipt is start "
+
purchaseDetails
.
productID
);
// 将收据发送到你的后端进行验证
final
String
receipt
=
purchaseDetails
.
verificationData
.
serverVerificationData
;
...
...
@@ -164,10 +165,10 @@ class SubscriptionService {
// 示例:发送收据到自己的服务器进行二次验证
Future
<
bool
>
_sendReceiptToBackend
(
String
receipt
,
String
orderid
)
async
{
var
result
=
_userAuthRepository
.
orderCheck
(
""
,
receipt
,
orderid
,
"ios"
);
var
result
=
_userAuthRepository
.
orderCheck
(
""
,
receipt
,
orderid
,
"ios"
,
1
);
//var data = result['data'] as Map<String, dynamic>?;
//debugPrint(result);
debugPrint
(
"[info] _sendReceiptToBackend is done
receipt is "
+
receipt
);
debugPrint
(
"[info] _sendReceiptToBackend is done
"
);
return
true
;
}
...
...
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