ver1.00.00

update2
This commit is contained in:
spasolreisa
2026-04-21 01:28:53 +08:00
parent f5f62c828d
commit 603772bc81
11 changed files with 346 additions and 286 deletions

View File

@@ -1,10 +1,21 @@
import com.android.build.api.dsl.SigningConfig
import java.util.Properties
plugins { plugins {
id("com.android.application") id("com.android.application")
id("kotlin-android") id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin") id("dev.flutter.flutter-gradle-plugin")
} }
// 加载 key.properties 配置 👇
val keystoreProperties = Properties()
val keystoreFile = rootProject.file("key.properties")
if (keystoreFile.exists()) {
keystoreFile.inputStream().use { stream ->
keystoreProperties.load(stream)
}
}
android { android {
namespace = "org.ast.unionapp" namespace = "org.ast.unionapp"
compileSdk = flutter.compileSdkVersion compileSdk = flutter.compileSdkVersion
@@ -20,25 +31,37 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "org.ast.unionapp" applicationId = "org.ast.unionapp"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName
} }
// 签名配置 👇
signingConfigs {
create("release") {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. // 启用正式签名(替换原来的 debug
// Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.getByName("release")
signingConfig = signingConfigs.getByName("debug") isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
} }
} }
flutter { flutter {
source = "../.." source = "../.."
} }

View File

@@ -1,8 +1,24 @@
allprojects { allprojects {
repositories { repositories {
// ✅ 阿里云 Maven 镜像(推荐,稳定快速)
maven { url = uri("https://maven.aliyun.com/repository/google") }
maven { url = uri("https://maven.aliyun.com/repository/public") }
maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
maven { url = uri("https://storage.googleapis.com/download.flutter.io") }
// ✅ 腾讯云 Maven 镜像(备用)
// maven { url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/") }
// 官方源(放在最后作为备用)
google() google()
mavenCentral() mavenCentral()
maven { url = uri("https://storage.googleapis.com/download.flutter.io") } }
configurations.all {
resolutionStrategy {
force("androidx.work:work-runtime:2.8.1")
force("androidx.work:work-runtime-ktx:2.8.1")
}
} }
} }

View File

@@ -3,3 +3,4 @@ distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
org.gradle.java.home=/Users/spasolreisa/Library/Java/JavaVirtualMachines/jbr-17.0.14/Contents/Home

View File

@@ -2,8 +2,10 @@ import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
// 新增导入
import 'package:zxing2/qrcode.dart';
import 'package:image/image.dart' as img;
import '../../providers/user_provider.dart'; import '../../providers/user_provider.dart';
@@ -22,19 +24,13 @@ class _BindAccountPageState extends State<BindAccountPage> {
String? _statusMessage; String? _statusMessage;
File? _selectedImageFile; // 用户选择的原始二维码截图 File? _selectedImageFile; // 用户选择的原始二维码截图
// 条码扫描器
final BarcodeScanner _barcodeScanner = BarcodeScanner(
formats: [BarcodeFormat.qrCode],
);
@override @override
void dispose() { void dispose() {
_qrContentController.dispose(); _qrContentController.dispose();
_barcodeScanner.close();
super.dispose(); super.dispose();
} }
// 1. 选择图片并识别二维码 // 1. 选择图片并识别二维码 (使用 zxing2替代 ML Kit)
Future<void> _pickImageAndScan() async { Future<void> _pickImageAndScan() async {
try { try {
final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery); final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery);
@@ -42,33 +38,79 @@ class _BindAccountPageState extends State<BindAccountPage> {
setState(() { setState(() {
_isProcessing = true; _isProcessing = true;
_statusMessage = "正在识别二维码..."; _statusMessage = "正在加载图片...";
_selectedImageFile = File(pickedFile.path); _selectedImageFile = File(pickedFile.path);
}); });
final inputImage = InputImage.fromFilePath(pickedFile.path); // 读取图片字节
final List<Barcode> barcodes = await _barcodeScanner.processImage(inputImage); final bytes = await pickedFile.readAsBytes();
// 使用 image 库解码图片为 RGB 数据
final img.Image? decodedImage = img.decodeImage(bytes);
if (decodedImage == null) {
throw Exception("无法解析图片格式");
}
setState(() { setState(() {
_isProcessing = false; _statusMessage = "正在解析二维码...";
}); });
if (barcodes.isNotEmpty && barcodes.first.rawValue != null) { final reader = QRCodeReader();
final String code = barcodes.first.rawValue!;
try {
// 【修复点开始】
// 1. 获取 Uint8List (RGBA 格式)
final Uint8List rgbaBytes = decodedImage.getBytes(order: img.ChannelOrder.rgba);
// 2. 将 Uint8List 转换为 Int32List
// 注意:这需要底层字节序匹配。大多数现代移动设备是 Little Endian。
// Uint8List 的长度必须是 4 的倍数RGBA 每个像素4字节这通常成立。
final Int32List pixels = Int32List.view(rgbaBytes.buffer);
// 3. 创建 LuminanceSource
// ZXing 的 RGBLuminanceSource 期望 Int32List其中每个 int 代表一个像素 (0xAARRGGBB 或类似格式)
// 由于 image 库给出的是 RGBA (0xRR, 0xGG, 0xBB, 0xAA),直接转换可能导致颜色通道错位,
// 但 ZXing 主要关注亮度(灰度),通常 RGBA 直接转 Int32 也能被正确二值化识别,
// 如果识别失败,可能需要手动重排字节为 ARGB。
final source = RGBLuminanceSource(
decodedImage.width,
decodedImage.height,
pixels
);
// 【修复点结束】
final binarizer = HybridBinarizer(source);
final bitmap = BinaryBitmap(binarizer);
final result = reader.decode(bitmap);
if (result != null && result.text != null) {
setState(() {
_qrContentController.text = result.text!;
_statusMessage = "识别成功";
});
} else {
setState(() {
_statusMessage = "未识别到二维码,请手动输入";
});
}
} catch (e) {
// 捕获 zxing 内部的 NotFoundException 等
print("ZXing Error: $e"); // 调试用
setState(() { setState(() {
_qrContentController.text = code; _statusMessage = "未在图中找到有效二维码";
_statusMessage = "识别成功";
});
} else {
setState(() {
_statusMessage = "未识别到二维码,请手动输入";
}); });
} }
} catch (e) { } catch (e) {
setState(() {
_statusMessage = "识别出错: $e";
});
} finally {
setState(() { setState(() {
_isProcessing = false; _isProcessing = false;
_statusMessage = "识别失败: $e";
}); });
} }
} }
@@ -92,7 +134,9 @@ class _BindAccountPageState extends State<BindAccountPage> {
}); });
try { try {
// 下载背景图用于隐写
final httpClient = HttpClient(); final httpClient = HttpClient();
// 建议在实际生产环境中添加 timeout
final request = await httpClient.getUrl(Uri.parse('https://union.godserver.cn/assets/jpeg/20180621142015_5FmGZ-wYXkyL4y.jpeg')); final request = await httpClient.getUrl(Uri.parse('https://union.godserver.cn/assets/jpeg/20180621142015_5FmGZ-wYXkyL4y.jpeg'));
final response = await request.close(); final response = await request.close();
final bytes = <int>[]; final bytes = <int>[];
@@ -101,6 +145,9 @@ class _BindAccountPageState extends State<BindAccountPage> {
} }
imageBytes = Uint8List.fromList(bytes); imageBytes = Uint8List.fromList(bytes);
// 关闭 client 以释放资源
httpClient.close();
if (imageBytes == null || imageBytes.isEmpty) throw Exception("图片数据无效"); if (imageBytes == null || imageBytes.isEmpty) throw Exception("图片数据无效");
setState(() { setState(() {
@@ -108,7 +155,6 @@ class _BindAccountPageState extends State<BindAccountPage> {
}); });
// 调用 Provider // 调用 Provider
// 注意:这里 segaId 参数其实传的是 QR Code 的内容
final userProvider = context.read<UserProvider>(); final userProvider = context.read<UserProvider>();
final result = await userProvider.uploadStegImage(imageBytes, segaId: qrContent); final result = await userProvider.uploadStegImage(imageBytes, segaId: qrContent);
@@ -122,10 +168,13 @@ class _BindAccountPageState extends State<BindAccountPage> {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("${result['msg']}"), backgroundColor: Colors.green, duration: const Duration(seconds: 5)), SnackBar(content: Text("${result['msg']}"), backgroundColor: Colors.green, duration: const Duration(seconds: 5)),
); );
// 绑定成功后,通常建议刷新用户信息 // 绑定成功后,刷新用户信息
await userProvider.initUser(); await userProvider.initUser();
// 可选:清空输入或跳转
// _qrContentController.clear();
// Navigator.of(context).pop();
} else { } else {
// 后端返回 500 或其他错误
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("${result['msg']}"), backgroundColor: Colors.red, duration: const Duration(seconds: 5)), SnackBar(content: Text("${result['msg']}"), backgroundColor: Colors.red, duration: const Duration(seconds: 5)),
); );
@@ -276,7 +325,7 @@ class _BindAccountPageState extends State<BindAccountPage> {
child: Text( child: Text(
_statusMessage!, _statusMessage!,
style: TextStyle( style: TextStyle(
color: _statusMessage!.contains("失败") || _statusMessage!.contains("错误") ? Colors.redAccent : Colors.white70, color: _statusMessage!.contains("失败") || _statusMessage!.contains("错误") || _statusMessage!.contains("未识别") ? Colors.redAccent : Colors.white70,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),

View File

@@ -77,6 +77,8 @@ class _LoginPageState extends State<LoginPage> {
final isDark = theme.brightness == Brightness.dark; final isDark = theme.brightness == Brightness.dark;
return Scaffold( return Scaffold(
// 关键修复1resizeToAvoidBottomInset = false防止键盘弹出重绘崩溃
resizeToAvoidBottomInset: false,
backgroundColor: isDark ? Colors.black : Colors.white, backgroundColor: isDark ? Colors.black : Colors.white,
appBar: AppBar( appBar: AppBar(
title: Text(isRegisterMode ? '创建账号' : '欢迎回来'), title: Text(isRegisterMode ? '创建账号' : '欢迎回来'),
@@ -96,215 +98,217 @@ class _LoginPageState extends State<LoginPage> {
), ),
alignment: Alignment.center, alignment: Alignment.center,
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: Transform.translate( child: SingleChildScrollView(
offset: const Offset(0, -30), // 关键修复2让滚动视图正常工作
child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(),
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 400), constraints: BoxConstraints(
child: Card( minHeight: MediaQuery.of(context).size.height - 100,
elevation: 8, ),
shadowColor: _pinkColor.withOpacity(0.3), child: Center(
shape: RoundedRectangleBorder( child: Transform.translate(
borderRadius: BorderRadius.circular(20), offset: const Offset(0, -30),
), child: ConstrainedBox(
color: isDark ? Colors.grey[850] : Colors.white, constraints: const BoxConstraints(maxWidth: 400),
child: Padding( child: Card(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32), elevation: 8, shadowColor: _pinkColor.withOpacity(0.3),
child: Column( shape: RoundedRectangleBorder(
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(20),
children: [ ),
// 头像/图标区域 - 已修改为黑白粉主题 color: isDark ? Colors.grey[850] : Colors.white,
Container( child: Padding(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
decoration: BoxDecoration( child: Column(
color: _pinkColor.withOpacity(0.15), mainAxisSize: MainAxisSize.min,
shape: BoxShape.circle, children: [
), Container(
child: Icon( padding: const EdgeInsets.all(20),
// 更换为更美观的人物头像类图标 decoration: BoxDecoration(
isRegisterMode ? Icons.person_add_rounded : Icons.person_rounded, color: _pinkColor.withOpacity(0.15),
size: 48, shape: BoxShape.circle,
color: _pinkColor, ),
), child: Icon(
), isRegisterMode ? Icons.person_add_rounded : Icons.person_rounded,
const SizedBox(height: 24), size: 48,
color: _pinkColor,
Text( ),
isRegisterMode ? '注册新账号' : '账号登录',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black87,
),
),
const SizedBox(height: 8),
Text(
isRegisterMode ? '请填写以下信息' : '请输入您的凭证以继续',
style: TextStyle(
fontSize: 14,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
if (errorMessage.isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.red.withOpacity(0.3)),
), ),
child: Row( const SizedBox(height: 24),
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 20), Text(
const SizedBox(width: 8), isRegisterMode ? '注册新账号' : '账号登录',
Expanded( style: TextStyle(
child: Text( fontSize: 24,
errorMessage, fontWeight: FontWeight.bold,
style: const TextStyle(color: Colors.red, fontSize: 13), color: isDark ? Colors.white : Colors.black87,
),
),
const SizedBox(height: 8),
Text(
isRegisterMode ? '请填写以下信息' : '请输入您的凭证以继续',
style: TextStyle(
fontSize: 14,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
if (errorMessage.isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.red.withOpacity(0.3)),
),
child: Row(
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(
errorMessage,
style: const TextStyle(color: Colors.red, fontSize: 13),
),
),
],
),
),
TextField(
controller: usernameController,
enabled: !isLoading,
decoration: InputDecoration(
labelText: '用户名',
prefixIcon: const Icon(Icons.person_outline, color: _pinkColor),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor, width: 2),
),
filled: true,
fillColor: isDark ? Colors.grey[800] : Colors.grey[50],
),
),
const SizedBox(height: 16),
TextField(
controller: passwordController,
obscureText: true,
enabled: !isLoading,
decoration: InputDecoration(
labelText: isRegisterMode ? '设置密码' : '密码 / TOTP验证码',
prefixIcon: const Icon(Icons.lock_outline, color: _pinkColor),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor, width: 2),
),
filled: true,
fillColor: isDark ? Colors.grey[800] : Colors.grey[50],
),
),
if (isRegisterMode) ...[
const SizedBox(height: 16),
TextField(
controller: inviterController,
enabled: !isLoading,
decoration: InputDecoration(
labelText: '邀请人 ID (可选)',
prefixIcon: const Icon(Icons.card_giftcard_outlined, color: _pinkColor),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor, width: 2),
),
filled: true,
fillColor: isDark ? Colors.grey[800] : Colors.grey[50],
),
),
],
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: isLoading ? null : submit,
style: ElevatedButton.styleFrom(
backgroundColor: _pinkColor,
foregroundColor: Colors.black,
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
), ),
), ),
], child: isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
),
)
: Text(
isRegisterMode ? '立即注册' : '登录',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
),
), ),
),
// 用户名输入框 const SizedBox(height: 16),
TextField(
controller: usernameController, TextButton(
enabled: !isLoading, onPressed: isLoading
decoration: InputDecoration( ? null
labelText: '用户名', : () {
prefixIcon: const Icon(Icons.person_outline, color: _pinkColor), setState(() {
border: OutlineInputBorder( isRegisterMode = !isRegisterMode;
borderRadius: BorderRadius.circular(12), errorMessage = '';
borderSide: const BorderSide(color: _pinkColor), });
},
child: Text(
isRegisterMode
? '已有账号?去登录'
: '没有账号?去注册',
style: const TextStyle(
color: _pinkColor,
fontWeight: FontWeight.w500,
fontSize: 14,
),
),
), ),
enabledBorder: OutlineInputBorder( ],
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor, width: 2),
),
filled: true,
fillColor: isDark ? Colors.grey[800] : Colors.grey[50],
),
), ),
const SizedBox(height: 16), ),
// 密码输入框
TextField(
controller: passwordController,
obscureText: true,
enabled: !isLoading,
decoration: InputDecoration(
labelText: isRegisterMode ? '设置密码' : '密码 / TOTP验证码',
prefixIcon: const Icon(Icons.lock_outline, color: _pinkColor),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor, width: 2),
),
filled: true,
fillColor: isDark ? Colors.grey[800] : Colors.grey[50],
),
),
if (isRegisterMode) ...[
const SizedBox(height: 16),
TextField(
controller: inviterController,
enabled: !isLoading,
decoration: InputDecoration(
labelText: '邀请人 ID (可选)',
prefixIcon: const Icon(Icons.card_giftcard_outlined, color: _pinkColor),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: _pinkColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: _pinkColor, width: 2),
),
filled: true,
fillColor: isDark ? Colors.grey[800] : Colors.grey[50],
),
),
],
const SizedBox(height: 24),
// 登录/注册按钮
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: isLoading ? null : submit,
style: ElevatedButton.styleFrom(
backgroundColor: _pinkColor,
foregroundColor: Colors.black,
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
),
)
: Text(
isRegisterMode ? '立即注册' : '登录',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
),
),
const SizedBox(height: 16),
// 切换登录/注册
TextButton(
onPressed: isLoading
? null
: () {
setState(() {
isRegisterMode = !isRegisterMode;
errorMessage = '';
});
},
child: Text(
isRegisterMode
? '已有账号?去登录'
: '没有账号?去注册',
style: const TextStyle(
color: _pinkColor,
fontWeight: FontWeight.w500,
fontSize: 14,
),
),
),
],
), ),
), ),
), ),

View File

@@ -6,18 +6,6 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <open_file_linux/open_file_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
} }

View File

@@ -3,13 +3,9 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
open_file_linux
url_launcher_linux
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
jni
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)

View File

@@ -49,6 +49,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "1.4.1" version: "1.4.1"
charcode:
dependency: transitive
description:
name: charcode
sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "1.4.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@@ -376,22 +384,6 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "2.1.3" version: "2.1.3"
google_mlkit_barcode_scanning:
dependency: "direct dev"
description:
name: google_mlkit_barcode_scanning
sha256: "965183a8cd5cef8477ceea5dbdf29c34a739cf0cfbf1bdad54cd3f9f1807afe5"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.10.0"
google_mlkit_commons:
dependency: transitive
description:
name: google_mlkit_commons
sha256: "046586b381cdd139f7f6a05ad6998f7e339d061bd70158249907358394b5f496"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.6.1"
gsettings: gsettings:
dependency: transitive dependency: transitive
description: description:
@@ -1181,6 +1173,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
zxing2:
dependency: "direct dev"
description:
name: zxing2
sha256: "2677c49a3b9ca9457cb1d294fd4bd5041cac6aab8cdb07b216ba4e98945c684f"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "0.2.4"
sdks: sdks:
dart: ">=3.11.3 <4.0.0" dart: ">=3.11.3 <4.0.0"
flutter: ">=3.38.4" flutter: ">=3.38.4"

View File

@@ -58,8 +58,8 @@ dev_dependencies:
open_file: ^3.3.2 open_file: ^3.3.2
webview_flutter: ^4.8.0 webview_flutter: ^4.8.0
image: ^4.0.17 image: ^4.0.17
google_mlkit_barcode_scanning: ^0.10.0 # 用于识别二维码/条形码
image_picker: ^1.0.4 image_picker: ^1.0.4
zxing2: ^0.2.3 # 新增:用于二维码识别
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec

View File

@@ -6,18 +6,6 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <geolocator_windows/geolocator_windows.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
} }

View File

@@ -3,14 +3,9 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
geolocator_windows
share_plus
url_launcher_windows
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
jni
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)