Commit 008466a0 by ethanlamzs

Merge branch 'feature-2607-iosbuild' into feature-2607

ios 线上 1.1.4版本内容 记录
2 parents c0cfeaad decaf318
...@@ -47,3 +47,5 @@ assets/static ...@@ -47,3 +47,5 @@ assets/static
pubspec.lock pubspec.lock
assets/dist.zip assets/dist.zip
macos/Podfile.lock macos/Podfile.lock
macos/Flutter/GeneratedPluginRegistrant.swift
windows/flutter/generated_plugins.cmake
...@@ -21,6 +21,8 @@ android { ...@@ -21,6 +21,8 @@ android {
ndkVersion = flutter.ndkVersion ndkVersion = flutter.ndkVersion
compileOptions { compileOptions {
// flutter_local_notifications 插件要求启用核心库脱糖
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
...@@ -91,6 +93,9 @@ flutter { ...@@ -91,6 +93,9 @@ flutter {
} }
dependencies { dependencies {
// flutter_local_notifications 插件要求启用核心库脱糖
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
// 添加 AppCompat 支持库(PrivacyActivity需要) // 添加 AppCompat 支持库(PrivacyActivity需要)
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
...@@ -104,7 +109,7 @@ dependencies { ...@@ -104,7 +109,7 @@ dependencies {
// OPPO // OPPO
//implementation("com.tencent.timpush:oppo:8.8.7357") //implementation("com.tencent.timpush:oppo:8.8.7357")
// vivo // vivo
//implementation("com.tencent.timpush:vivo:8.8.7357") implementation("com.tencent.timpush:vivo:8.8.7357")
// Honor // Honor
//implementation("com.tencent.timpush:honor:8.7.7201") //implementation("com.tencent.timpush:honor:8.7.7201")
// Meizu // Meizu
......
{"version":"1.0.1","cn.banxe.bxe":{"manifestPlaceholders":{"VIVO_APPKEY":"f7e37b20f48234c425d9e7f82fdd16c0","VIVO_APPID":"105993977","HONOR_APPID":""},"vivoPushBussinessId":"44580","oppoPushBussinessId":"46190","oppoPushAppKey":"922926ff488b4c2cb76bb4103ca8a93d","oppoPushAppSecret":"30636ddc19d94571aa1378db15d61ac0"}}
\ No newline at end of file \ No newline at end of file
{
"version": "1.0.1",
"cn.banxe.bxe": {
"manifestPlaceholders": {
"VIVO_APPKEY": "f7e37b20f48234c425d9e7f82fdd16c0",
"VIVO_APPID": "105993977",
"HONOR_APPID": ""
},
"vivoPushBussinessId": "44580"
}
}
\ No newline at end of file \ No newline at end of file
...@@ -5,8 +5,9 @@ if [ -z "$1" ]; then ...@@ -5,8 +5,9 @@ if [ -z "$1" ]; then
fi fi
env=$1 env=$1
_rebuild_=$2 ot=$2
_main_ver='1.0.' _rebuild_=$3
_main_ver='1.1.'
_ver=`date +%y%m%d%H%M` _ver=`date +%y%m%d%H%M`
base_root='/Users/ethanlam/works/gitlab/flutter_pros/appframe.git' base_root='/Users/ethanlam/works/gitlab/flutter_pros/appframe.git'
...@@ -47,12 +48,27 @@ if [ ! -z "$_rebuild_" ]; then ...@@ -47,12 +48,27 @@ if [ ! -z "$_rebuild_" ]; then
pod install pod install
fi fi
_ver_tmp=`date '+%y%m%d%H%M'`
echo 'build '
flutter build ios --build-number=$_ver_tmp
#16 #16
#flutter run --dart-define=env=$env --dart-define=version=$_main_ver$_ver -d 00008140-001068C93AB8801C if [ ! -z "$ot" ]; then
if [ "$ot" == '16' ]; then
flutter run --dart-define=env=$env --dart-define=version=$_main_ver$_ver -d 00008140-001068C93AB8801C
fi
#11 if [ "$ot" == '11' ]; then
#flutter run --dart-define=env=$env --dart-define=version=$_main_ver$_ver -d 00008030-001C75810E42402E flutter run --dart-define=env=$env --dart-define=version=$_main_ver$_ver -d 00008030-001C75810E42402E
fi
flutter build ios --build-number=$_ver 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
#11
#flutter run --dart-define=env=$env --dart-define=version=$_main_ver$_ver -d 00008030-001C75810E42402E
#flutter build ios --build-number=$_ver
...@@ -20,7 +20,7 @@ flutter pub get ...@@ -20,7 +20,7 @@ flutter pub get
#pod deintegrate #pod deintegrate
# 4. 清理 CocoaPods 本地缓存 (这一步很重要,ffmpeg 包很大,容易缓存损坏) # 4. 清理 CocoaPods 本地缓存 (这一步很重要,ffmpeg 包很大,容易缓存损坏)
pod cache clean --all #pod cache clean --all
# 5. 重新安装 Pods 并更新仓库索引 # 5. 重新安装 Pods 并更新仓库索引
# 注意:这一步可能比较慢,因为 ffmpeg 库非常大(几百MB),请保持网络通畅 # 注意:这一步可能比较慢,因为 ffmpeg 库非常大(几百MB),请保持网络通畅
......
...@@ -26,7 +26,7 @@ end ...@@ -26,7 +26,7 @@ end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
# pod 'TOCropViewController', :path => '/Users/ethanlam/works/base_env/flutter_envirs/extlibs/TOCropViewController.git/2.8.0' , :podspec => '/Users/ethanlam/works/base_env/flutter_envirs/extlibs/TOCropViewController.git/2.8.0/TOCropViewController.podspec' #pod 'TOCropViewController', :path => '/Users/ethanlam/works/base_env/flutter_envirs/extlibs/TOCropViewController.git/2.8.0' , :podspec => '/Users/ethanlam/works/base_env/flutter_envirs/extlibs/TOCropViewController.git/2.8.0/TOCropViewController.podspec'
pod 'SDWebImage', :git => 'https://gitee.com/mirrors/SDWebImage.git', :branch => '5.21.3', :modular_headers => true pod 'SDWebImage', :git => 'https://gitee.com/mirrors/SDWebImage.git', :branch => '5.21.3', :modular_headers => true
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
DC7B80922FF3602D0006BCCE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC7B80912FF3602D0006BCCE /* StoreKit.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
...@@ -70,6 +71,8 @@ ...@@ -70,6 +71,8 @@
DC39D7882EFB987F00D795A8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = en; path = en.lproj/Info.plist; sourceTree = "<group>"; }; DC39D7882EFB987F00D795A8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = en; path = en.lproj/Info.plist; sourceTree = "<group>"; };
DC39D7892EFB988000D795A8 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "zh-Hans"; path = "zh-Hans.lproj/Info.plist"; sourceTree = "<group>"; }; DC39D7892EFB988000D795A8 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "zh-Hans"; path = "zh-Hans.lproj/Info.plist"; sourceTree = "<group>"; };
DC4A6BC3E644F00288FAFDCD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DC4A6BC3E644F00288FAFDCD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DC7B80912FF3602D0006BCCE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
DCEFFEE63000FA7000F7B036 /* Testing.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; name = Testing.storekit; path = Runner/Testing.storekit; sourceTree = "<group>"; };
E94A65B4132ADF0336017236 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; E94A65B4132ADF0336017236 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
...@@ -87,6 +90,7 @@ ...@@ -87,6 +90,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
1600F8F364E182C3635C3546 /* Pods_Runner.framework in Frameworks */, 1600F8F364E182C3635C3546 /* Pods_Runner.framework in Frameworks */,
DC7B80922FF3602D0006BCCE /* StoreKit.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -115,6 +119,7 @@ ...@@ -115,6 +119,7 @@
97C146E51CF9000F007C117D = { 97C146E51CF9000F007C117D = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DCEFFEE63000FA7000F7B036 /* Testing.storekit */,
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
...@@ -153,6 +158,7 @@ ...@@ -153,6 +158,7 @@
9F7FE946B3449150A78BC577 /* Frameworks */ = { 9F7FE946B3449150A78BC577 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DC7B80912FF3602D0006BCCE /* StoreKit.framework */,
B2450CB3B5E968BD7CC513E6 /* Pods_Runner.framework */, B2450CB3B5E968BD7CC513E6 /* Pods_Runner.framework */,
DC4A6BC3E644F00288FAFDCD /* Pods_RunnerTests.framework */, DC4A6BC3E644F00288FAFDCD /* Pods_RunnerTests.framework */,
); );
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Profile"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
......
...@@ -84,7 +84,6 @@ import tencent_cloud_chat_push ...@@ -84,7 +84,6 @@ import tencent_cloud_chat_push
return true return true
} }
} }
// 可选:防止冲突的手势识别设置 // 可选:防止冲突的手势识别设置
...@@ -93,4 +92,5 @@ extension AppDelegate: UIGestureRecognizerDelegate { ...@@ -93,4 +92,5 @@ extension AppDelegate: UIGestureRecognizerDelegate {
// 如果需要同时识别,比如与 WebView 的滚动手势共存 // 如果需要同时识别,比如与 WebView 的滚动手势共存
return true return true
} }
}
\ No newline at end of file \ No newline at end of file
}
...@@ -57,6 +57,9 @@ class WebState extends Equatable { ...@@ -57,6 +57,9 @@ class WebState extends Equatable {
final int? userType; final int? userType;
final String? stuId; final String? stuId;
/// 通知点击等场景需要直接打开的 URL
final String? targetUrl;
/// getOrientationCmd /// getOrientationCmd
final bool orientationCmdFlag; final bool orientationCmdFlag;
final String orientationCmdMessage; final String orientationCmdMessage;
...@@ -99,6 +102,7 @@ class WebState extends Equatable { ...@@ -99,6 +102,7 @@ class WebState extends Equatable {
this.classCode, this.classCode,
this.userType, this.userType,
this.stuId, this.stuId,
this.targetUrl,
this.orientationCmdFlag = false, this.orientationCmdFlag = false,
this.orientationCmdMessage = '', this.orientationCmdMessage = '',
this.windowInfoCmdFlag = false, this.windowInfoCmdFlag = false,
...@@ -131,6 +135,7 @@ class WebState extends Equatable { ...@@ -131,6 +135,7 @@ class WebState extends Equatable {
String? classCode, String? classCode,
int? userType, int? userType,
String? stuId, String? stuId,
String? targetUrl,
bool? orientationCmdFlag, bool? orientationCmdFlag,
String? orientationCmdMessage, String? orientationCmdMessage,
bool? windowInfoCmdFlag, bool? windowInfoCmdFlag,
...@@ -162,6 +167,7 @@ class WebState extends Equatable { ...@@ -162,6 +167,7 @@ class WebState extends Equatable {
classCode: classCode ?? this.classCode, classCode: classCode ?? this.classCode,
userType: userType ?? this.userType, userType: userType ?? this.userType,
stuId: stuId ?? this.stuId, stuId: stuId ?? this.stuId,
targetUrl: targetUrl ?? this.targetUrl,
orientationCmdFlag: orientationCmdFlag ?? this.orientationCmdFlag, orientationCmdFlag: orientationCmdFlag ?? this.orientationCmdFlag,
orientationCmdMessage: orientationCmdMessage ?? this.orientationCmdMessage, orientationCmdMessage: orientationCmdMessage ?? this.orientationCmdMessage,
windowInfoCmdFlag: windowInfoCmdFlag ?? this.windowInfoCmdFlag, windowInfoCmdFlag: windowInfoCmdFlag ?? this.windowInfoCmdFlag,
...@@ -195,6 +201,7 @@ class WebState extends Equatable { ...@@ -195,6 +201,7 @@ class WebState extends Equatable {
classCode, classCode,
userType, userType,
stuId, stuId,
targetUrl,
orientationCmdFlag, orientationCmdFlag,
orientationCmdMessage, orientationCmdMessage,
windowInfoCmdFlag, windowInfoCmdFlag,
...@@ -394,6 +401,15 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver { ...@@ -394,6 +401,15 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
} }
void _loadHtml() { void _loadHtml() {
// 如果通过路由透传了 targetUrl(如通知点击场景),
// 优先在 WebView 中打开该 URL。
final targetUrl = state.targetUrl;
if (targetUrl != null && targetUrl.isNotEmpty) {
final String resolvedUrl = '${Constant.localServerUrl}/index.html#$targetUrl';
_controller.loadRequest(Uri.parse(resolvedUrl));
return;
}
var sharedPreferences = getIt.get<SharedPreferences>(); var sharedPreferences = getIt.get<SharedPreferences>();
var debug = sharedPreferences.getInt('debug') ?? 0; var debug = sharedPreferences.getInt('debug') ?? 0;
// 构造函数中已拦截判断未登录的情况进行了处理,所以这里不再处理未登录的情况 // 构造函数中已拦截判断未登录的情况进行了处理,所以这里不再处理未登录的情况
...@@ -452,7 +468,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver { ...@@ -452,7 +468,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
imService.registerPush(); imService.registerPush();
// 处理加群和退群 // 处理加群和退群
if (state.loginOpFlag) { if (state.loginOpFlag) {
// imService.joinAndLeaveGroup(state.userCode!); imService.joinAndLeaveGroup(state.userCode!);
} }
} else { } else {
debugPrint("缓存自动登录处,IM 登录失败"); debugPrint("缓存自动登录处,IM 登录失败");
......
...@@ -125,6 +125,6 @@ class Constant { ...@@ -125,6 +125,6 @@ class Constant {
static const String hasShownPrivacyFirstTimeKey = 'has_shown_privacy_first_time'; static const String hasShownPrivacyFirstTimeKey = 'has_shown_privacy_first_time';
/// 测试阶段使用 /// 测试阶段使用
static const bool needIM = false; static const bool needIM = true;
static const bool needUpgrade = true; static const bool needUpgrade = true;
} }
...@@ -50,6 +50,7 @@ import 'package:appframe/services/api_service.dart'; ...@@ -50,6 +50,7 @@ import 'package:appframe/services/api_service.dart';
import 'package:appframe/services/dispatcher.dart'; import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/services/im_service.dart'; import 'package:appframe/services/im_service.dart';
import 'package:appframe/services/local_server_service.dart'; import 'package:appframe/services/local_server_service.dart';
import 'package:appframe/services/notification_service.dart';
import 'package:appframe/services/player_service.dart'; import 'package:appframe/services/player_service.dart';
import 'package:appframe/services/recorder_service.dart'; import 'package:appframe/services/recorder_service.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
...@@ -241,6 +242,9 @@ Future<void> setupLocator() async { ...@@ -241,6 +242,9 @@ Future<void> setupLocator() async {
instanceName: "appApiService", instanceName: "appApiService",
); );
/// 通知服务
getIt.registerSingleton<NotificationService>(NotificationService());
/// imService /// imService
getIt.registerSingleton<ImService>(ImService()); getIt.registerSingleton<ImService>(ImService());
......
...@@ -19,6 +19,7 @@ import 'package:appframe/ui/pages/setting_v2/account_apple_page_v2.dart'; ...@@ -19,6 +19,7 @@ import 'package:appframe/ui/pages/setting_v2/account_apple_page_v2.dart';
import 'package:appframe/ui/pages/setting_v2/account_logoff_page_v2.dart'; import 'package:appframe/ui/pages/setting_v2/account_logoff_page_v2.dart';
import 'package:appframe/ui/pages/setting_v2/account_page_v2.dart'; import 'package:appframe/ui/pages/setting_v2/account_page_v2.dart';
import 'package:appframe/ui/pages/setting_v2/account_phone_page_v2.dart'; import 'package:appframe/ui/pages/setting_v2/account_phone_page_v2.dart';
import 'package:appframe/ui/pages/subscription_page.dart';
import 'package:appframe/ui/pages/web_page.dart'; import 'package:appframe/ui/pages/web_page.dart';
import 'package:appframe/ui/widgets/ios_edge_swipe_detector.dart'; import 'package:appframe/ui/widgets/ios_edge_swipe_detector.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
...@@ -130,6 +131,12 @@ final GoRouter router = GoRouter( ...@@ -130,6 +131,12 @@ final GoRouter router = GoRouter(
return const PreviewMediaPage(); return const PreviewMediaPage();
}, },
), ),
GoRoute(
path: '/iosbuytest',
builder: (BuildContext context, GoRouterState state) {
return const SubscriptionPage();
},
),
], ],
); );
......
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:appframe/config/constant.dart'; import 'package:appframe/config/constant.dart';
import 'package:appframe/config/locator.dart'; import 'package:appframe/config/locator.dart';
import 'package:appframe/data/repositories/user_auth_repository.dart'; import 'package:appframe/data/repositories/user_auth_repository.dart';
import 'package:appframe/services/dispatcher.dart'; import 'package:appframe/services/dispatcher.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_localization/flutter_localization.dart';
import 'package:appframe/services/subscription_service_ios.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
class XeCreateOrderHandler extends MessageHandler { class XeCreateOrderHandler extends MessageHandler {
...@@ -19,6 +22,8 @@ class XeCreateOrderHandler extends MessageHandler { ...@@ -19,6 +22,8 @@ class XeCreateOrderHandler extends MessageHandler {
// 超时定时器 // 超时定时器
Timer? _timeoutTimer; Timer? _timeoutTimer;
final SubscriptionService _subService = SubscriptionService();
XeCreateOrderHandler() { XeCreateOrderHandler() {
_fluwx = getIt.get<Fluwx>(); _fluwx = getIt.get<Fluwx>();
_userAuthRepository = getIt.get<UserAuthRepository>(); _userAuthRepository = getIt.get<UserAuthRepository>();
...@@ -26,6 +31,8 @@ class XeCreateOrderHandler extends MessageHandler { ...@@ -26,6 +31,8 @@ class XeCreateOrderHandler extends MessageHandler {
@override @override
Future<dynamic> handleMessage(params) async { Future<dynamic> handleMessage(params) async {
print("############## handleMessage #############");
// 从 params 中提取支付参数 // 从 params 中提取支付参数
final String chargeCode = params['chargeCode'] as String? ?? ''; final String chargeCode = params['chargeCode'] as String? ?? '';
final int durationType = params['durationType'] as int? ?? 0; final int durationType = params['durationType'] as int? ?? 0;
...@@ -50,13 +57,28 @@ class XeCreateOrderHandler extends MessageHandler { ...@@ -50,13 +57,28 @@ class XeCreateOrderHandler extends MessageHandler {
'phone=$phone, userCode=$userCode, tbxStuId=$tbxStuId, stuId=$stuId, ' 'phone=$phone, userCode=$userCode, tbxStuId=$tbxStuId, stuId=$stuId, '
'ext=$ext'); 'ext=$ext');
// 1. 检查微信是否安装 // 1. 请求后端获取预支付订单信息
final deviceType = Platform.isIOS?"ios":"andorid";
if (deviceType == 'andorid'){
return await _wx_pay_proc_(userCode, tbxStuId, chargeCode, deviceType, phone, stuId, ext, duration, durationType, totalFee, renew, useCoin);
}else if (deviceType == 'ios'){
// 暂时不支持使用学币扣减
// 执行ios支付
await _subService.initialize();
return await _ios_pay_proc_(userCode, tbxStuId, chargeCode, deviceType, phone, stuId, ext, duration, durationType, totalFee, renew, false);
}
}
// 执行微信支付
Future<dynamic> _wx_pay_proc_ (String userCode, tbxStuId, chargeCode,deviceType,phone,stuId,ext,int duration, durationType, totalFee,bool renew, useCoin) async{
// 2. 检查微信是否安装
if (!await _fluwx.isWeChatInstalled) { if (!await _fluwx.isWeChatInstalled) {
throw Exception('设备上未安装微信App,不支持微信支付'); throw Exception('设备上未安装微信App,不支持微信支付');
} }
// 2. 请求后端获取预支付订单信息
final deviceType = 'android';
var result = await _userAuthRepository.createOrder(userCode, tbxStuId, chargeCode, duration, durationType, totalFee, var result = await _userAuthRepository.createOrder(userCode, tbxStuId, chargeCode, duration, durationType, totalFee,
renew, phone, stuId, ext, useCoin ? 1 : 0, deviceType); renew, phone, stuId, ext, useCoin ? 1 : 0, deviceType);
if (result == null) { if (result == null) {
...@@ -83,14 +105,14 @@ class XeCreateOrderHandler extends MessageHandler { ...@@ -83,14 +105,14 @@ class XeCreateOrderHandler extends MessageHandler {
final paySign = data['paySign'] as String; final paySign = data['paySign'] as String;
final wxTradeNo = data['wxTradeNo'] as String; final wxTradeNo = data['wxTradeNo'] as String;
debugPrint('prepayId: $prepayId'); debugPrint('_wx_pay_proc_ => prepayId: $prepayId');
debugPrint('nonceStr: $nonceStr'); debugPrint('_wx_pay_proc_ => nonceStr: $nonceStr');
debugPrint('timestamp: $timestamp'); debugPrint('_wx_pay_proc_ => timestamp: $timestamp');
debugPrint('paySign: $paySign'); debugPrint('_wx_pay_proc_ => paySign: $paySign');
debugPrint('appId: $appId'); debugPrint('_wx_pay_proc_ => appId: $appId');
debugPrint('partnerId: $partnerId'); debugPrint('_wx_pay_proc_ => partnerId: $partnerId');
debugPrint('packageValue: $packageValue'); debugPrint('_wx_pay_proc_ => packageValue: $packageValue');
debugPrint('wxTradeNo: $wxTradeNo'); debugPrint('_wx_pay_proc_ => wxTradeNo: $wxTradeNo');
if (nonceStr.isEmpty || paySign.isEmpty || wxTradeNo.isEmpty) { if (nonceStr.isEmpty || paySign.isEmpty || wxTradeNo.isEmpty) {
throw Exception('支付参数获取失败'); throw Exception('支付参数获取失败');
...@@ -155,6 +177,8 @@ class XeCreateOrderHandler extends MessageHandler { ...@@ -155,6 +177,8 @@ class XeCreateOrderHandler extends MessageHandler {
} finally { } finally {
_cleanup(); _cleanup();
} }
} }
/// Fluwx 响应监听器 /// Fluwx 响应监听器
...@@ -174,4 +198,82 @@ class XeCreateOrderHandler extends MessageHandler { ...@@ -174,4 +198,82 @@ class XeCreateOrderHandler extends MessageHandler {
_timeoutTimer = null; _timeoutTimer = null;
_payCompleter = null; _payCompleter = null;
} }
// 执行ios的微信支付
Future<dynamic> _ios_pay_proc_ (String userCode, tbxStuId, chargeCode,deviceType,phone,stuId,ext,int duration, durationType, totalFee,bool renew, useCoin) async{
// 暂时用固定的价格
var result = await _userAuthRepository.createOrder(userCode, tbxStuId, chargeCode, duration, durationType, totalFee,
renew, phone, stuId, ext, useCoin ? 1 : 0, deviceType);
print(result);
// map[nonceStr:qNfHK6a95jjJkwzDkh0h3fhfUVuS0jZ9 paySign: timeStamp:1783497438 wxTradeNo:to1281644408384671744]
var data = result['data'] as Map<String, dynamic>?;
if (data == null) {
throw Exception('订单生成失败');
}
// 3. 从后端响应中提取预支付ID
final wxTradeNo = data['wxTradeNo'] as String?;
if (wxTradeNo == null || wxTradeNo.isEmpty) {
throw Exception('订单生成失败');
}
// 4. 从后端响应中提取支付参数(nonceStr、timestamp、paySign 由后端生成)
final timestamp = data['timeStamp'] as int;
//debugPrint('_ios_pay_proc_ => timestamp: $timestamp');
debugPrint('_ios_pay_proc_ => wxTradeNo: $wxTradeNo');
if (wxTradeNo.isEmpty) {
throw Exception('支付参数获取失败');
}
// 为了调试,先模拟
var product;
var packageName = "";
if (totalFee.toString()=="4990"){
packageName="月卡";
}else if (totalFee.toString()=="12900"){
packageName="季卡";
}else if (totalFee.toString()=="20900"){
packageName="半年卡";
}else if (totalFee.toString()=="29900"){
packageName="年卡";
}
for (var p in _subService.products) {
// 因为带了一个¥符号
//debugPrint('checking ==> 产品ID: ${p.id}, 标题: ${p.title}, 价格: ${p.price}');
if (p.title.toString().indexOf(packageName)>0){
product = p;
debugPrint('match =====> 产品ID: ${p.id}, 标题: ${p.title}, 价格: ${p.price}');
break;
}
//
}
if(product==null){
throw Exception('订单生成失败');
}
print("match product is "+product.price);
var isOk = await _subService.buySubscription(product, userCode, tbxStuId,wxTradeNo);
print("[info] _subService.buySubscription res is "+isOk.toString());
if (isOk==true){
return {"orderUnique": wxTradeNo, "orderState": 1};
}else{
return {"orderUnique": wxTradeNo, "orderState": 0};
}
// throw Exception('已取消支付');
}
} }
...@@ -18,7 +18,7 @@ class SubsRepository { ...@@ -18,7 +18,7 @@ class SubsRepository {
{ {
"type": type, "type": type,
"userid": userid, "userid": userid,
"classCode": classCode, "classCodes": classCode,
}, },
); );
return resp.statusCode == HttpStatus.ok ? resp.data : null; return resp.statusCode == HttpStatus.ok ? resp.data : null;
......
...@@ -162,4 +162,23 @@ class UserAuthRepository { ...@@ -162,4 +162,23 @@ class UserAuthRepository {
} }
} }
// 检查ios的订单是否已经订阅
Future<dynamic> orderCheck(String userId,String receipt,String orderid, String platform,int isSandbox ) async {
try {
Response resp = await _appService.post(
'/api/v1/comm/user/ordercheck',
{
"userId": userId,
"receipt": receipt,
"orderid":orderid,
"platform": platform,
"isSandbox":isSandbox,
},
);
return resp.statusCode == HttpStatus.ok ? resp.data : null;
} on DioException {
return null;
}
}
} }
...@@ -10,7 +10,7 @@ import 'package:flutter/material.dart'; ...@@ -10,7 +10,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:appframe/services/subscription_service_ios.dart';
import 'app.dart'; import 'app.dart';
void main() async { void main() async {
...@@ -21,6 +21,11 @@ void main() async { ...@@ -21,6 +21,11 @@ void main() async {
await _initH5Version(); await _initH5Version();
await _initIOSGesture(); await _initIOSGesture();
if (Platform.isIOS){
SubscriptionService _subService = SubscriptionService();
_subService.initialize();
}
runApp(const App()); runApp(const App());
} }
......
...@@ -6,6 +6,7 @@ import 'package:appframe/data/models/message/h5_message.dart'; ...@@ -6,6 +6,7 @@ import 'package:appframe/data/models/message/h5_message.dart';
import 'package:appframe/data/models/message/h5_resp.dart'; import 'package:appframe/data/models/message/h5_resp.dart';
import 'package:appframe/data/repositories/message/upload_cancel_handler.dart'; import 'package:appframe/data/repositories/message/upload_cancel_handler.dart';
import 'package:appframe/data/repositories/message/upload_start_handler.dart'; import 'package:appframe/data/repositories/message/upload_start_handler.dart';
import 'package:flutter/widgets.dart';
// 消息处理器抽象类 // 消息处理器抽象类
abstract class MessageHandler { abstract class MessageHandler {
...@@ -35,7 +36,6 @@ class MessageDispatcher { ...@@ -35,7 +36,6 @@ class MessageDispatcher {
Future<void> dispatch(String message, Function callback, {WebCubit? webCubit}) async { Future<void> dispatch(String message, Function callback, {WebCubit? webCubit}) async {
final Map<String, dynamic> data = json.decode(message); final Map<String, dynamic> data = json.decode(message);
H5Message h5Message = H5Message.fromJson(data); H5Message h5Message = H5Message.fromJson(data);
var handler = _handlers[h5Message.cmd]; var handler = _handlers[h5Message.cmd];
if (handler == null) { if (handler == null) {
try { try {
......
import 'dart:convert';
import 'dart:io';
import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class NotificationService {
final FlutterLocalNotificationsPlugin _plugin = FlutterLocalNotificationsPlugin();
bool _isInitialized = false;
bool get isInitialized => _isInitialized;
/// 初始化通知插件
Future<void> initialize() async {
if (_isInitialized) return;
const androidSettings = AndroidInitializationSettings('@mipmap/launcher_icon');
const iosSettings = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const settings = InitializationSettings(android: androidSettings, iOS: iosSettings);
final result = await _plugin.initialize(
settings,
onDidReceiveNotificationResponse: _onNotificationResponse,
);
_isInitialized = result ?? false;
if (_isInitialized) {
debugPrint('NotificationService 初始化成功');
// Android 13+ 需要请求通知权限
if (Platform.isAndroid) {
final androidPlugin = _plugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
await androidPlugin?.requestNotificationsPermission();
}
} else {
debugPrint('NotificationService 初始化失败');
}
}
/// 处理通知点击(供外部调用,如离线推送点击)
void handleNotificationClick(String? payload) {
debugPrint('[notification_service] handleNotificationClick payload: $payload');
// 通过 /reload 中转路由跳转,确保即使当前已在 /web,
// GoRouter 也会完整重建 WebPage 并加载新的 targetUrl。
final targetUrl = _buildTargetUrl(payload);
debugPrint('[notification_service] targetUrl: $targetUrl');
if (targetUrl != null && targetUrl.isNotEmpty) {
router.go(
'/reload',
extra: {'targetUrl': targetUrl},
);
} else {
router.go('/web');
}
}
/// 前台本地通知点击回调处理
void _onNotificationResponse(NotificationResponse response) {
debugPrint('[notification_service] Notification clicked, payload: ${response.payload}');
handleNotificationClick(response.payload);
}
/// 解析通知 payload,结合 auth_roles 缓存拼接目标 URL。
/// payload 格式:{"func": "homework", "uniqueCode": "...", "classCode": "..."}
/// 返回示例:/h5/login/pages/applogin?sessionCode=xxx&userCode=xxx&classCode=xxx&userType=2&stuId=xxx&page=homeworkdetail&uniqueCode=xxx
String? _buildTargetUrl(String? payload) {
if (payload == null || payload.isEmpty) return null;
try {
final data = jsonDecode(payload) as Map<String, dynamic>;
final func = data['func'] as String?;
final uniqueCode = data['uniqueCode'] as String?;
final classCode = data['classCode'] as String?;
if (uniqueCode == null || uniqueCode.isEmpty || classCode == null || classCode.isEmpty) {
debugPrint('[notification_service] payload 缺少 uniqueCode 或 classCode');
return null;
}
final prefs = getIt.get<SharedPreferences>();
final rolesJson = prefs.getString('auth_roles') ?? '';
if (rolesJson.isEmpty) {
debugPrint('[notification_service] auth_roles 缓存为空');
return null;
}
final roles = jsonDecode(rolesJson) as List<dynamic>;
Map<String, dynamic>? matchedRole;
for (final role in roles) {
if (role is Map<String, dynamic> && role['classCode']?.toString() == classCode) {
matchedRole = role;
break;
}
}
if (matchedRole == null) {
debugPrint('[notification_service] 未找到与 classCode=$classCode 匹配的 role');
return null;
}
final stuId = matchedRole['stuId']?.toString() ?? '';
final sessionCode = prefs.getString('auth_sessionCode') ?? '';
final userCode = prefs.getString('auth_userCode') ?? '';
var funcPage = '';
if (func == 'homework') {
funcPage = 'page=homeworkdetail&uniqueCode=$uniqueCode';
} else if (func == 'clockin') {
funcPage = 'page=clockdetail&clockUnique=$uniqueCode';
} else {
debugPrint('[notification_service] 不支持功能的类型: $func');
return null;
}
return '/h5/login/pages/applogin?'
'sessionCode=$sessionCode&'
'userCode=$userCode&'
'classCode=$classCode&'
'userType=2&'
'stuId=$stuId&'
'$funcPage';
} catch (e, stackTrace) {
debugPrint('[notification_service] 解析 payload 失败: $e\n$stackTrace');
return null;
}
}
/// 显示手机通知(懒初始化:首次调用自动触发初始化)
Future<void> showNotification({
required int id,
required String title,
required String body,
String? payload,
}) async {
// 懒初始化:首次调用时自动初始化
if (!_isInitialized) {
await initialize();
}
const androidDetails = AndroidNotificationDetails(
'homework_message_channel',
'作业消息通知',
channelDescription: '接收作业消息推送通知',
importance: Importance.high,
priority: Priority.high,
);
const iosDetails = DarwinNotificationDetails();
const details = NotificationDetails(android: androidDetails, iOS: iosDetails);
await _plugin.show(id, title, body, details, payload: payload);
debugPrint('NotificationService showNotification: id=$id, title=$title, body=$body');
}
}
import 'package:appframe/config/routes.dart'; import 'package:appframe/config/routes.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
/// ///
/// 用于重新加载的中间路由 /// 用于重新加载的中间路由
/// 通知点击等场景先跳转到此页,再转发 targetUrl 到 /web,
/// 确保 GoRouter 完整重建 WebPage 并加载目标 URL。
/// ///
class ReloadPage extends StatefulWidget { class ReloadPage extends StatefulWidget {
const ReloadPage({super.key}); const ReloadPage({super.key});
...@@ -23,7 +26,12 @@ class _ReloadPageState extends State<ReloadPage> { ...@@ -23,7 +26,12 @@ class _ReloadPageState extends State<ReloadPage> {
} }
void _performPostDisplayOperations() { void _performPostDisplayOperations() {
router.go('/web'); final extra = GoRouterState.of(context).extra;
if (extra is Map<String, dynamic> && extra['targetUrl'] != null) {
router.go('/web', extra: extra);
} else {
router.go('/web');
}
} }
@override @override
......
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:appframe/services/subscription_service_ios.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
// subscription_page.dart
class SubscriptionPage extends StatefulWidget {
const SubscriptionPage({super.key});
@override
State<SubscriptionPage> createState() => _SubscriptionPageState();
}
class _SubscriptionPageState extends State<SubscriptionPage> {
final SubscriptionService _subService = SubscriptionService();
bool _isInitialized = false;
@override
void initState() {
super.initState();
_initService();
}
Future<void> _initService() async {
await _subService.initialize();
setState(() => _isInitialized = true);
}
Future<void> _buy(ProductDetails product) async {
if (!_isInitialized) return;
try {
await _subService.buySubscription(product,"","","");
} catch (e) {
// 显示出错信息
debugPrint(e.toString());
}
}
@override
Widget build(BuildContext context) {
if (!_isInitialized) return CircularProgressIndicator();
// return ListView.builder(
// itemCount: _subService.products.length,
// itemBuilder: (context, index) {
// final product = _subService.products[index];
// return ListTile(
// title: Text(product.title),
// subtitle: Text(product.id),
// trailing: ElevatedButton(
// onPressed: () => _buy(product),
// child: Text(product.price),
// ),
// );
// },
// );
return Scaffold(
body: Center(
child: ListView.builder(
itemCount: _subService.products.length,
itemBuilder: (context, index) {
final product = _subService.products[index];
return ListTile(
title: Text(product.title),
subtitle: Text(product.description),
trailing: ElevatedButton(
onPressed: () => _buy(product),
child: Text(product.price),
),
);
},
),
),
);
}
@override
void dispose() {
// _subService.dispose();
super.dispose();
}
}
\ No newline at end of file \ No newline at end of file
...@@ -25,6 +25,7 @@ class WebPage extends StatelessWidget { ...@@ -25,6 +25,7 @@ class WebPage extends StatelessWidget {
var classCode = extraData?['classCode']; var classCode = extraData?['classCode'];
var userType = extraData?['userType']; var userType = extraData?['userType'];
var stuId = extraData?['stuId']; var stuId = extraData?['stuId'];
var targetUrl = extraData?['targetUrl'];
if (sessionCode == null || sessionCode == '') { if (sessionCode == null || sessionCode == '') {
loginOpFlag = false; loginOpFlag = false;
...@@ -49,6 +50,7 @@ class WebPage extends StatelessWidget { ...@@ -49,6 +50,7 @@ class WebPage extends StatelessWidget {
classCode: classCode, classCode: classCode,
userType: userType, userType: userType,
stuId: stuId, stuId: stuId,
targetUrl: targetUrl,
), ),
); );
return webCubit; return webCubit;
......
import 'dart:convert';
import 'package:appframe/config/constant.dart'; import 'package:appframe/config/constant.dart';
import 'package:appframe/config/locator.dart'; import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart'; import 'package:appframe/config/routes.dart';
...@@ -89,6 +91,8 @@ class LoginUtil { ...@@ -89,6 +91,8 @@ class LoginUtil {
sharedPreferences.setString('auth_className', className); sharedPreferences.setString('auth_className', className);
sharedPreferences.setString('auth_stuName', stuName); sharedPreferences.setString('auth_stuName', stuName);
sharedPreferences.setString('auth_relation', relation); sharedPreferences.setString('auth_relation', relation);
// 用于处理点击推送通知时,获取跳转到指定页面的参数
sharedPreferences.setString('auth_roles', jsonEncode(roles));
if (loginType == 'router') { if (loginType == 'router') {
router.go( router.go(
......
...@@ -12,9 +12,11 @@ import device_info_plus ...@@ -12,9 +12,11 @@ import device_info_plus
import ffmpeg_kit_flutter_new import ffmpeg_kit_flutter_new
import file_picker import file_picker
import flutter_image_compress_macos import flutter_image_compress_macos
import flutter_local_notifications
import flutter_localization import flutter_localization
import flutter_sound import flutter_sound
import geolocator_apple import geolocator_apple
import in_app_purchase_storekit
import mobile_scanner import mobile_scanner
import network_info_plus import network_info_plus
import open_file_mac import open_file_mac
...@@ -23,10 +25,12 @@ import path_provider_foundation ...@@ -23,10 +25,12 @@ import path_provider_foundation
import photo_manager import photo_manager
import shared_preferences_foundation import shared_preferences_foundation
import sign_in_with_apple import sign_in_with_apple
import sqflite_darwin
import tencent_cloud_chat_sdk import tencent_cloud_chat_sdk
import url_launcher_macos import url_launcher_macos
import video_player_avfoundation import video_player_avfoundation
import volume_controller import volume_controller
import wakelock_plus
import webview_flutter_wkwebview import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
...@@ -37,9 +41,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ...@@ -37,9 +41,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin")) FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterLocalizationPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalizationPlugin")) FlutterLocalizationPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalizationPlugin"))
FlutterSoundPlugin.register(with: registry.registrar(forPlugin: "FlutterSoundPlugin")) FlutterSoundPlugin.register(with: registry.registrar(forPlugin: "FlutterSoundPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
InAppPurchasePlugin.register(with: registry.registrar(forPlugin: "InAppPurchasePlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin"))
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin")) OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
...@@ -48,9 +54,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ...@@ -48,9 +54,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PhotoManagerPlugin.register(with: registry.registrar(forPlugin: "PhotoManagerPlugin")) PhotoManagerPlugin.register(with: registry.registrar(forPlugin: "PhotoManagerPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
TencentCloudChatSdkPlugin.register(with: registry.registrar(forPlugin: "TencentCloudChatSdkPlugin")) TencentCloudChatSdkPlugin.register(with: registry.registrar(forPlugin: "TencentCloudChatSdkPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin")) VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
} }
...@@ -6,7 +6,7 @@ fi ...@@ -6,7 +6,7 @@ fi
env=$1 env=$1
_rebuild_=$2 _rebuild_=$2
_main_ver='1.0.' _main_ver='1.1.'
_ver=`date +%y%m%d%H%M` _ver=`date +%y%m%d%H%M`
base_root='/Users/ethanlam/works/gitlab/flutter_pros/appframe.git' base_root='/Users/ethanlam/works/gitlab/flutter_pros/appframe.git'
......
name: appframe name: appframe
description: "app frame project." description: "app frame project."
publish_to: 'none' publish_to: 'none'
version: 1.1.0+8 version: 1.1.4
environment: environment:
sdk: ">=3.5.0 <4.0.0" sdk: ">=3.5.0 <4.0.0"
...@@ -62,6 +62,8 @@ dependencies: ...@@ -62,6 +62,8 @@ dependencies:
# --- Apple 登录 --- # --- Apple 登录 ---
sign_in_with_apple: ^7.0.1 sign_in_with_apple: ^7.0.1
in_app_purchase: ^3.2.3 # 使用最新稳定版
http: ^1.2.0 # 用于服务端验证
# --- 音视频与直播 (重灾区) --- # --- 音视频与直播 (重灾区) ---
# 确保 ffmpeg_kit 版本与你的架构兼容。 # 确保 ffmpeg_kit 版本与你的架构兼容。
...@@ -95,6 +97,7 @@ dependencies: ...@@ -95,6 +97,7 @@ dependencies:
cupertino_icons: ^1.0.8 cupertino_icons: ^1.0.8
fluttertoast: ^9.0.0 fluttertoast: ^9.0.0
flutter_local_notifications: ^19.5.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
......
...@@ -14,6 +14,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ...@@ -14,6 +14,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_local_notifications_windows
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!