fix: 增加iap的跳转

This commit is contained in:
speakeloudest 2026-01-23 07:06:36 -08:00
parent b96008d6dc
commit 57a47874be
4 changed files with 153 additions and 12 deletions

View File

@ -762,9 +762,11 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/HiddifyPacketTunnel.entitlements; CODE_SIGN_ENTITLEMENTS = PacketTunnel/HiddifyPacketTunnel.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NJRRF427XB; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = armv7; EXCLUDED_ARCHS = armv7;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
@ -790,6 +792,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord-PacketTunnel";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
@ -815,9 +818,11 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnelRelease.entitlements; CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnelRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NJRRF427XB; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = armv7; EXCLUDED_ARCHS = armv7;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
@ -843,6 +848,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord-PacketTunnel";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
@ -866,9 +872,11 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/HiddifyPacketTunnel.entitlements; CODE_SIGN_ENTITLEMENTS = PacketTunnel/HiddifyPacketTunnel.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NJRRF427XB; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = armv7; EXCLUDED_ARCHS = armv7;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
@ -894,6 +902,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord-PacketTunnel";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
@ -971,9 +980,11 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NJRRF427XB; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7; "EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -1005,6 +1016,7 @@
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn; "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
@ -1200,9 +1212,11 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NJRRF427XB; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7; "EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64"; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
@ -1234,6 +1248,7 @@
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn; "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
@ -1255,9 +1270,11 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NJRRF427XB; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7; "EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -1289,6 +1306,7 @@
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn; "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;

View File

@ -176,6 +176,7 @@ class KRInviteView extends GetView<KRInviteController> {
maxLength: 10, maxLength: 10,
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
decoration: InputDecoration( decoration: InputDecoration(
counterText: '',
hintText: '填码领免费时长...', hintText: '填码领免费时长...',
hintStyle: const TextStyle(color: Color(0xFFA6A6A6)), hintStyle: const TextStyle(color: Color(0xFFA6A6A6)),
filled: true, filled: true,

View File

@ -7,6 +7,7 @@ import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'dart:io'; import 'dart:io';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../../../common/app_run_data.dart'; import '../../../common/app_run_data.dart';
import '../../../common/app_config.dart'; import '../../../common/app_config.dart';
@ -19,12 +20,14 @@ import '../../../network/http_util.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
// import 'package:flutter_stripe/flutter_stripe.dart'; // import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:in_app_purchase/in_app_purchase.dart'; import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_storekit/store_kit_2_wrappers.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:kaer_with_panels/app/model/response/kr_purchase_order_no.dart'; import 'package:kaer_with_panels/app/model/response/kr_purchase_order_no.dart';
import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart'; import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart';
import 'package:kaer_with_panels/app/services/iap/iap_pending_order_service.dart'; import 'package:kaer_with_panels/app/services/iap/iap_pending_order_service.dart';
import 'package:kaer_with_panels/app/services/iap/iap_service.dart'; import 'package:kaer_with_panels/app/services/iap/iap_service.dart';
import '../../../services/kr_site_config_service.dart';
/// ///
/// ///
@ -86,6 +89,12 @@ class KRPurchaseMembershipController extends GetxController {
print('💳 [PurchaseMembership] ❌ 写入调试日志失败: $e'); print('💳 [PurchaseMembership] ❌ 写入调试日志失败: $e');
} }
// curversion site/config
final siteConfigService = KRSiteConfigService();
if (siteConfigService.getCurVersion().isEmpty) {
siteConfigService.fetchSiteConfig();
}
kr_initializeData(); kr_initializeData();
} }
@ -1006,6 +1015,60 @@ class KRPurchaseMembershipController extends GetxController {
return; return;
} }
// 🔧
try {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
final String currentVersion = packageInfo.version;
final String curVersion = KRSiteConfigService().getCurVersion();
print('💳 [IAP] 支付检查: App版本=$currentVersion, 服务端参考版本=$curVersion');
if (curVersion.isNotEmpty) {
// version版本小于等于 curversion
if (_kr_compareVersion(currentVersion, curVersion) <= 0) {
// apple id (HK)(TW)
// 使 StoreKit SKStorefront App Store
// 使 StoreKit 2 App Store
String storefrontCountryCode = '';
try {
// StoreKit 2 API
final Storefront storefront = Storefront();
final String storefrontCountryCode = await storefront.countryCode();
print('💳 [IAP] Storefront 2 地区检查: countryCode=$storefrontCountryCode');
} catch (e) {
print('💳 [IAP] 获取 Storefront 2 信息失败, 尝试使用系统地区作为后备: $e');
storefrontCountryCode = Get.deviceLocale?.countryCode ?? '';
}
// H5 ( 2 3 )
const h5WhiteList = [
'HKG', //
'TWN', //
'MAC', //
'SGP', //
'MYS', // 西
'THA', //
'VNM', //
'PHL', //
];
if (h5WhiteList.contains(storefrontCountryCode.toUpperCase())) {
final String token = KRAppRunData.getInstance().kr_token ?? '';
final String url = 'https://hifastvpn.com/login/$token';
print('💳 [IAP] 符合跳转条件 (Storefront: $storefrontCountryCode),跳转至网页支付: $url');
final Uri uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
return; //
}
}
}
}
} catch (e) {
print('💳 [IAP] 版本或地区检查时发生异常: $e');
}
final KRIpaPayment iapParams = (checkoutResponse.ipa == null || final KRIpaPayment iapParams = (checkoutResponse.ipa == null ||
(checkoutResponse.ipa?.productId.isEmpty ?? true)) (checkoutResponse.ipa?.productId.isEmpty ?? true))
? KRIpaPayment( ? KRIpaPayment(
@ -1115,4 +1178,27 @@ class KRPurchaseMembershipController extends GetxController {
return; // return; //
} }
} }
///
///
/// -1: v1 < v2
/// 0: v1 == v2
/// 1: v1 > v2
int _kr_compareVersion(String v1, String v2) {
if (v1.isEmpty || v2.isEmpty) return 0;
try {
List<String> list1 = v1.split('.');
List<String> list2 = v2.split('.');
int len = list1.length > list2.length ? list1.length : list2.length;
for (int i = 0; i < len; i++) {
int n1 = i < list1.length ? int.tryParse(list1[i]) ?? 0 : 0;
int n2 = i < list2.length ? int.tryParse(list2[i]) ?? 0 : 0;
if (n1 > n2) return 1;
if (n1 < n2) return -1;
}
} catch (e) {
print('版本比较失败: $e');
}
return 0;
}
} }

View File

@ -299,6 +299,42 @@ class KRSiteConfigService extends ChangeNotifier {
return _siteConfig?.site.deviceLimit ?? '0'; return _siteConfig?.site.deviceLimit ?? '0';
} }
///
///
/// customData curVersion
///
/// String
String getCurVersion() {
try {
final customData = _siteConfig?.site.customData ?? '';
if (customData.isEmpty) return '';
final Map<String, dynamic> jsonMap =
jsonDecode(customData) as Map<String, dynamic>;
final value = jsonMap['curVersion'];
return value == null ? '' : value.toString();
} catch (_) {
return '';
}
}
///
///
/// customData shareUrl
///
/// String
String getShareUrl() {
try {
final customData = _siteConfig?.site.customData ?? '';
if (customData.isEmpty) return '';
final Map<String, dynamic> jsonMap =
jsonDecode(customData) as Map<String, dynamic>;
final value = jsonMap['shareUrl'];
return value == null ? '' : value.toString();
} catch (_) {
return '';
}
}
/// ///
void reset() { void reset() {
_siteConfig = null; _siteConfig = null;