完善用户接口

This commit is contained in:
胡天 2023-07-18 12:56:02 +08:00
parent af3d954e75
commit de74c4c2a2
22 changed files with 836 additions and 28 deletions

8
lib/config/cache.dart Normal file
View File

@ -0,0 +1,8 @@
//
const CacheEnable = false;
//
const CacheMaxAge = 1000;
//
const CacheMaxCount = 100;

4
lib/config/server.dart Normal file
View File

@ -0,0 +1,4 @@
/// Api地址
const String ServerApiUrl = "http://172.31.163.87:4523/m1/2998542-0-default";
const CryptoSalt = "E1pWsyfiy@R@X#qn17!StJNdZK1fFF8iV6ffN!goZkqt#JxO";

14
lib/config/storage.dart Normal file
View File

@ -0,0 +1,14 @@
/// -
const String StorageUserProfileKey = 'user_profile';
/// -
const String StorageUserTokenKey = 'user_token';
///
const String StorageDeviceFirstOpenKey = 'device_first_open';
/// cacheKey
const String StorageIndexNewsCacheKey= 'cache_index_news';
///
const String StorageLanguageCode = 'language_code';

View File

@ -1,6 +0,0 @@
class UserLoginRequest {
String email;
String password;
UserLoginRequest({required this.email, required this.password});
}

70
lib/data/model/user.dart Normal file
View File

@ -0,0 +1,70 @@
//
class UserRegisterRequest {
String email;
String password;
UserRegisterRequest({
required this.email,
required this.password,
});
factory UserRegisterRequest.fromJson(Map<String, dynamic> json) =>
UserRegisterRequest(
email: json["email"],
password: json["password"],
);
Map<String, dynamic> toJson() => {
"email": email,
"password": password,
};
}
//
class UserLoginRequest {
String email;
String password;
UserLoginRequest({
required this.email,
required this.password,
});
factory UserLoginRequest.fromJson(Map<String, dynamic> json) =>
UserLoginRequest(
email: json["email"],
password: json["password"],
);
Map<String, dynamic> toJson() => {
"email": email,
"password": password,
};
}
//
class UserLoginResponse {
String? accessToken;
String? displayName;
List<String>? channels;
UserLoginResponse({
this.accessToken,
this.displayName,
this.channels,
});
factory UserLoginResponse.fromJson(Map<String, dynamic> json) =>
UserLoginResponse(
accessToken: json["access_token"],
displayName: json["display_name"],
channels: List<String>.from(json["channels"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"access_token": accessToken,
"display_name": displayName,
"channels":
channels == null ? [] : List<dynamic>.from(channels!.map((x) => x)),
};
}

View File

@ -0,0 +1,40 @@
//
import 'package:news_getx/data/model/user.dart';
import 'package:news_getx/utils/http.dart';
class UserAPI {
///
static Future<UserLoginResponse> login(UserLoginRequest? data) async {
UserLoginResponse response = await HttpUtil().post(
"/user/login",
data: data?.toJson(),
);
return response;
}
///
static Future<UserRegisterRequest> register(UserRegisterRequest request, {
UserRegisterRequest? data,
}) async {
var response = await HttpUtil().post(
'/user/register',
data: data?.toJson(),
);
return UserRegisterRequest.fromJson(response);
}
/// Profile
static Future<UserLoginResponse> profile() async {
var response = await HttpUtil().post(
'/user/profile',
);
return UserLoginResponse.fromJson(response);
}
/// Logout
static Future logout() async {
return await HttpUtil().post(
'/user/logout',
);
}
}

View File

@ -0,0 +1,23 @@
import 'package:news_getx/data/model/user.dart';
import 'package:news_getx/data/provider/user.dart';
class UserRepository {
Future<UserLoginResponse> login(UserLoginRequest request) {
return UserAPI.login(request);
}
Future<UserRegisterRequest> register(
UserRegisterRequest request, {
UserRegisterRequest? data,
}) {
return UserAPI.register(request, data: data);
}
Future<UserLoginResponse> profile() {
return UserAPI.profile();
}
Future logout() {
return UserAPI.logout();
}
}

View File

@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:news_getx/config/storage.dart';
import 'package:news_getx/data/services/storage.dart';
import 'package:package_info_plus/package_info_plus.dart';
class ConfigService extends GetxService {
static ConfigService get to => Get.find();
bool isFirstOpen = false;
PackageInfo? _platform;
String get version => _platform?.version ?? "-";
bool get isRelease => bool.fromEnvironment("dart.vm.product");
Locale locale = Locale("en", "US");
List<Locale> languages = [
Locale('en', 'US'),
Locale('zh', 'CN'),
];
@override
void onInit() {
super.onInit();
isFirstOpen = StorageService.to.getBool(StorageDeviceFirstOpenKey);
}
Future<void> getPlatform() async {
_platform = await PackageInfo.fromPlatform();
}
// APP
Future<bool> saveAlreadyOpen() {
return StorageService.to.setBool(StorageDeviceFirstOpenKey, false);
}
void onInitLocale() {
String langCode = StorageService.to.getString(StorageLanguageCode);
if (langCode .isEmpty) return;
int index = languages.indexWhere((element) {
return element.languageCode == langCode;
});
if (index < 0) return;
locale = languages[index];
}
void onLocaleUpdate(Locale value) {
locale = value;
// app的语言
Get.updateLocale(value);
StorageService.to.setString(StorageLanguageCode, value.languageCode);
}
}

View File

@ -0,0 +1,41 @@
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class StorageService extends GetxService {
static StorageService get to => Get.find<StorageService>();
late final SharedPreferences _prefs;
Future<StorageService> init() async {
_prefs = await SharedPreferences.getInstance();
return this;
}
Future<bool> setString(String key, String value) async {
return await _prefs.setString(key, value);
}
Future<bool> setBool(String key, bool value) async {
return await _prefs.setBool(key, value);
}
Future<bool> setList(String key, List<String> value) async {
return await _prefs.setStringList(key, value);
}
String getString(String key) {
return _prefs.getString(key) ?? '';
}
bool getBool(String key) {
return _prefs.getBool(key) ?? false;
}
List<String> getList(String key) {
return _prefs.getStringList(key) ?? [];
}
Future<bool> remove(String key) async {
return await _prefs.remove(key);
}
}

View File

@ -0,0 +1,61 @@
import 'dart:convert';
import 'package:get/get.dart';
import 'package:news_getx/config/storage.dart';
import 'package:news_getx/data/model/user.dart';
import 'package:news_getx/data/provider/user.dart';
import 'package:news_getx/data/services/storage.dart';
class UserService extends GetxService {
static UserService get to => Get.find();
//
var _isLogin = false.obs;
// token
String token = "";
// profile
var _profile = UserLoginResponse().obs;
bool get hasToken => token.isNotEmpty;
@override
void onInit() {
super.onInit();
token = StorageService.to.getString(StorageUserTokenKey);
var profileOffline = StorageService.to.getString(StorageUserProfileKey);
if (profileOffline.isNotEmpty) {
_profile(UserLoginResponse.fromJson(jsonDecode(profileOffline)));
}
}
// token
Future<void> setToken(String value) async {
await StorageService.to.setString(StorageUserTokenKey, value);
token = value;
}
// profile
Future<void> getProfile() async {
if (token.isEmpty) return;
UserLoginResponse result = await UserAPI.profile();
_profile(result);
_isLogin.value = true;
StorageService.to.setString(StorageUserProfileKey, jsonEncode(result));
}
// profile
Future<void> saveProfile(UserLoginResponse profile) async {
_isLogin.value = true;
await StorageService.to.setString(StorageUserProfileKey, jsonEncode(profile));
}
//
Future<void> onLogout() async {
if (_isLogin.value) await UserAPI.logout();
await StorageService.to.remove(StorageUserTokenKey);
_isLogin.value = false;
token = '';
}
}

View File

@ -1,5 +1,9 @@
import 'package:get/get.dart';
class NotFoundController extends GetxController {
// title
final _title = "".obs;
set title(value) => _title.value = value;
get title => _title.value;
}

View File

@ -8,6 +8,10 @@ class NotFoundPage extends GetView<NotFoundController> {
@override
Widget build(BuildContext context) {
return Container();
return Obx(() {
return Center(
child: Obx(() => Text(controller.title)),
);
});
}
}

View File

@ -1,10 +1,15 @@
import 'package:get/get.dart';
import 'package:news_getx/data/repository/user_repository.dart';
import 'sign_in_controller.dart';
class SignInBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => SignInController());
Get.lazyPut(
() => SignInController(
repository: UserRepository(),
),
);
}
}

View File

@ -1,17 +1,26 @@
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:news_getx/data/model/user.dart';
import 'package:news_getx/data/repository/user_repository.dart';
import 'package:news_getx/data/services/user.dart';
import 'package:news_getx/modules/widgets/toast.dart';
import 'package:news_getx/routes/app_pages.dart';
import 'package:news_getx/utils/security.dart';
import 'package:news_getx/utils/validator.dart';
class SignInController extends GetxController {
final UserRepository repository;
// email的控制器
final TextEditingController emailController = TextEditingController();
//
final TextEditingController passwordController = TextEditingController();
SignInController({required this.repository});
//
handleNavSignUp(){
handleNavSignUp() {
// TODO
Get.toNamed(AppRoutes.Signup);
}
@ -28,11 +37,20 @@ class SignInController extends GetxController {
return;
}
if(!checkStringLength(passwordController.text, 6)){
if (!checkStringLength(passwordController.text, 6)) {
toastInfo(msg: '密码不能小于6位');
return;
}
UserLoginRequest request = UserLoginRequest(
email: emailController.text,
password: cryptoSha256(passwordController.text),
);
UserLoginResponse response = await repository.login(request);
UserService.to.saveProfile(response);
Get.offAndToNamed(AppRoutes.Application);
}

View File

@ -1,10 +1,13 @@
import 'package:get/get.dart';
import 'package:news_getx/data/repository/user_repository.dart';
import 'sign_up_controller.dart';
class SignUpBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => SignUpController());
Get.lazyPut(() => SignUpController(
repository: UserRepository(),
));
}
}

View File

@ -1,23 +1,32 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:news_getx/data/model/user.dart';
import 'package:news_getx/data/repository/user_repository.dart';
import 'package:news_getx/modules/widgets/toast.dart';
import 'package:news_getx/routes/app_pages.dart';
import 'package:news_getx/utils/security.dart';
import 'package:news_getx/utils/validator.dart';
class SignUpController extends GetxController {
final UserRepository repository;
// email的控制器
final TextEditingController fullNameController = TextEditingController();
// email的控制器
final TextEditingController emailController = TextEditingController();
//
final TextEditingController passwordController = TextEditingController();
SignUpController({required this.repository});
//
handleNavPop() {
Get.back();
}
handleRegister() {
handleRegister() async {
if (!checkStringLength(fullNameController.text, 5)) {
toastInfo(msg: '用户名不能小于5位');
return;
@ -31,7 +40,12 @@ class SignUpController extends GetxController {
return;
}
toastInfo(msg: '注册成功');
UserRegisterRequest params = UserRegisterRequest(
email: emailController.text, password: cryptoSha256(passwordController.text),
);
await repository.register(params);
Get.back();
}

View File

@ -1,4 +1,6 @@
import 'package:get/get.dart';
import 'package:news_getx/modules/not_found/not_found_binding.dart';
import 'package:news_getx/modules/not_found/not_found_page.dart';
import 'package:news_getx/modules/sign_in/sign_in_binding.dart';
import 'package:news_getx/modules/sign_in/sign_in_page.dart';
import 'package:news_getx/modules/sign_up/sign_up_binding.dart';
@ -10,6 +12,7 @@ part './app_routes.dart';
abstract class AppPages {
static final pages = [
//
GetPage(
name: AppRoutes.Initial,
page: () => WelcomePage(),
@ -24,6 +27,11 @@ abstract class AppPages {
name: AppRoutes.Signup,
page: () => SignUpPage(),
binding: SignUpBinding(),
)
),
GetPage(
name: AppRoutes.NotFound,
page: () => NotFoundPage(),
binding: NotFoundBinding(),
),
];
}

379
lib/utils/http.dart Normal file
View File

@ -0,0 +1,379 @@
import 'package:dio/dio.dart';
import 'package:get/get.dart' hide FormData;
import 'package:news_getx/config/cache.dart';
import 'package:news_getx/config/server.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:news_getx/data/services/user.dart';
import 'package:news_getx/utils/loading.dart';
/*
* http
*
*
* https://github.com/cfug/dio/blob/main/dio/README-ZH.md
*
* 4 5
* https://github.com/cfug/dio/blob/main/dio/migration_guide.md
*/
class HttpUtil {
late Dio dio;
CancelToken cancelToken = CancelToken();
// dio对象
static HttpUtil _instance = HttpUtil._internal();
factory HttpUtil() => _instance;
HttpUtil._internal() {
// BaseOptionsOptionsRequestOptions
BaseOptions options = BaseOptions(
// ,
baseUrl: ServerApiUrl,
//.
connectTimeout: Duration(seconds: 10),
//
receiveTimeout: Duration(seconds: 5),
// Http请求头.
headers: {},
/// Content-Type"application/json; charset=utf-8".
/// "application/x-www-form-urlencoded",
/// `Headers.formUrlEncodedContentType`, [Dio]
/// .
contentType: "application/json; charset=utf-8",
/// [responseType] ()
/// [ResponseType] `JSON`, `STREAM`, `PLAIN`.
///
/// `JSON`, content-type为"application/json"dio json对象
/// 使 `STREAM`.
///
/// ()使 `PLAIN`.
responseType: ResponseType.json,
);
dio = Dio(options);
// Cookie管理
CookieJar cookieJar = CookieJar();
// CookieManager
dio.interceptors.add(CookieManager(cookieJar));
//
dio.interceptors.add(InterceptorsWrapper(
onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
// Do something before request is sent
return handler.next(options);
// resolve一个Response对象 `handler.resolve(response)`
// then会被调用then中返回的数据将是你的自定义response.
//
// ,`DioException`,`handler.reject(error)`
// catchError会被调用
},
onResponse: (response, handler) {
// Do something with response data
return handler.next(response);
// , reject `DioException`,`handler.reject(error)`
// catchError会被调用
},
onError: (DioException err, ErrorInterceptorHandler handler) {
// Do something with response error
Loading.dismiss();
ErrorEntity entity = createErrorEntity(err);
onError(entity);
return handler.next(err);
// resolve `Response`,`handler.resolve(response)`
// then会被调用then中返回的数据将是你的自定义response.
},
));
}
///
void onError(ErrorEntity errorEntity) {
print(
'error.code -> ${errorEntity.code}, error.message -> ${errorEntity.message}');
switch (errorEntity.code) {
case 401:
//
UserService.to.onLogout();
EasyLoading.showError(errorEntity.message);
break;
default:
EasyLoading.showError('未知错误');
break;
}
}
//
ErrorEntity createErrorEntity(DioException error) {
switch (error.type) {
case DioExceptionType.cancel:
return ErrorEntity(code: -1, message: "请求取消");
case DioExceptionType.connectionTimeout:
return ErrorEntity(code: -1, message: "连接超时");
case DioExceptionType.sendTimeout:
return ErrorEntity(code: -1, message: "请求超时");
case DioExceptionType.receiveTimeout:
return ErrorEntity(code: -1, message: "响应超时");
case DioExceptionType.badResponse:
{
try {
int errCode =
error.response != null ? error.response!.statusCode! : -1;
// String errMsg = error.response.statusMessage;
// return ErrorEntity(code: errCode, message: errMsg);
switch (errCode) {
case 400:
return ErrorEntity(code: errCode, message: "请求语法错误");
case 401:
return ErrorEntity(code: errCode, message: "没有权限");
case 403:
return ErrorEntity(code: errCode, message: "服务器拒绝执行");
case 404:
return ErrorEntity(code: errCode, message: "无法连接服务器");
case 405:
return ErrorEntity(code: errCode, message: "请求方法被禁止");
case 500:
return ErrorEntity(code: errCode, message: "服务器内部错误");
case 502:
return ErrorEntity(code: errCode, message: "无效的请求");
case 503:
return ErrorEntity(code: errCode, message: "服务器挂了");
case 505:
return ErrorEntity(code: errCode, message: "不支持HTTP协议请求");
default:
{
// return ErrorEntity(code: errCode, message: "未知错误");
return ErrorEntity(
code: errCode,
message: error.response != null
? error.response!.statusMessage!
: "",
);
}
}
} on Exception catch (_) {
return ErrorEntity(code: -1, message: "未知错误");
}
}
default:
{
return ErrorEntity(code: -1, message: error.message ?? "未定义错误");
}
}
}
///
/// cancel token cancel token取消时使cancel token的请求都会被取消
///
void cancelRequests(CancelToken token) {
token.cancel("cancelled");
}
///
Map<String, dynamic>? getAuthorizationHeader() {
var headers = <String, dynamic>{};
if (Get.isRegistered<UserService>() && UserService.to.hasToken) {
headers['Authorization'] = 'Bearer ${UserService.to.token}';
}
return headers;
}
/// restful get
/// refresh false
/// noCache true
/// list false
/// cacheKey key
/// cacheDisk
Future<dynamic> get(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
bool refresh = false,
bool noCache = !CacheEnable,
bool list = false,
String cacheKey = '',
bool cacheDisk = false,
}) async {
Options requestOptions = options ?? Options();
// 使
requestOptions.extra ??= <String, dynamic>{
"refresh": refresh,
"noCache": noCache,
"list": list,
"cacheKey": cacheKey,
"cacheDisk": cacheDisk,
};
//
requestOptions.headers ??= {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
var response = await dio.get(
path,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
);
return response.data;
}
/// restful post
Future post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
Options requestOptions = options ?? Options();
requestOptions.headers = requestOptions.headers ?? {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
var response = await dio.post(
path,
data: data,
queryParameters: queryParameters,
options: requestOptions,
cancelToken: cancelToken,
);
return response.data;
}
/// restful put
Future put(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
Options requestOptions = options ?? Options();
requestOptions.headers = requestOptions.headers ?? {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
var response = await dio.put(
path,
data: data,
queryParameters: queryParameters,
options: requestOptions,
cancelToken: cancelToken,
);
return response.data;
}
/// restful patch
Future patch(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
Options requestOptions = options ?? Options();
requestOptions.headers = requestOptions.headers ?? {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
var response = await dio.patch(
path,
data: data,
queryParameters: queryParameters,
options: requestOptions,
cancelToken: cancelToken,
);
return response.data;
}
/// restful delete
Future delete(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
Options requestOptions = options ?? Options();
requestOptions.headers = requestOptions.headers ?? {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
var response = await dio.delete(
path,
data: data,
queryParameters: queryParameters,
options: requestOptions,
cancelToken: cancelToken,
);
return response.data;
}
/// restful post form
Future postForm(
String path, {
required Map<String, dynamic> data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
Options requestOptions = options ?? Options();
requestOptions.headers = requestOptions.headers ?? {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
var response = await dio.post(
path,
data: FormData.fromMap(data),
queryParameters: queryParameters,
options: requestOptions,
cancelToken: cancelToken,
);
return response.data;
}
/// restful post Stream
Future postStream(
String path, {
dynamic data,
int dataLength = 0,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
Options requestOptions = options ?? Options();
requestOptions.headers = requestOptions.headers ?? {};
Map<String, dynamic>? authorization = getAuthorizationHeader();
if (authorization != null) {
requestOptions.headers!.addAll(authorization);
}
requestOptions.headers!.addAll({
Headers.contentLengthHeader: dataLength.toString(),
});
var response = await dio.post(
path,
data: Stream.fromIterable(data.map((e) => [e])),
queryParameters: queryParameters,
options: requestOptions,
cancelToken: cancelToken,
);
return response.data;
}
}
class ErrorEntity implements Exception {
int code = -1;
String message = "";
ErrorEntity({required this.code, required this.message});
@override
String toString() {
if (message.isEmpty) return "Exception";
return "Exception: code $code, $message";
}
}

38
lib/utils/loading.dart Normal file
View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
class Loading {
Loading() {
// loading的配置
EasyLoading.instance
..displayDuration = const Duration(milliseconds: 2000)
..indicatorType = EasyLoadingIndicatorType.ring
..loadingStyle = EasyLoadingStyle.custom
..indicatorSize = 35.0
..lineWidth = 2
..radius = 10.0
..progressColor = Colors.white
..backgroundColor = Colors.black.withOpacity(0.7)
..indicatorColor = Colors.white
..textColor = Colors.white
..maskColor = Colors.black.withOpacity(0.6)
..userInteractions = true
..dismissOnTap = false
..maskType = EasyLoadingMaskType.custom;
}
static void show([String? text]) {
//
EasyLoading.instance.userInteractions = false;
EasyLoading.show(status: text ?? "Loading...");
}
static void toast(String text) {
EasyLoading.showToast(text);
}
static void dismiss() {
EasyLoading.instance.userInteractions = true;
EasyLoading.dismiss();
}
}

10
lib/utils/security.dart Normal file
View File

@ -0,0 +1,10 @@
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:news_getx/config/server.dart';
String cryptoSha256(String input) {
var bytes = utf8.encode(input + CryptoSalt);
var digest = sha256.convert(bytes);
return digest.toString();
}

View File

@ -69,10 +69,10 @@ packages:
dependency: "direct main"
description:
name: cookie_jar
sha256: d1cc6516a190ba667941f722b6365d202caff3dacb38de24268b8d6ff1ec8a1d
sha256: "1024f3a52bee181fc8f10f4a359085471587d7406323090a53a7171bc0aa5c37"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
version: "4.0.5"
crypto:
dependency: "direct main"
description:
@ -109,18 +109,18 @@ packages:
dependency: "direct main"
description:
name: dio
sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
sha256: a9d76e72985d7087eb7c5e7903224ae52b337131518d127c554b9405936752b8
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.6"
version: "5.2.1+1"
dio_cookie_manager:
dependency: "direct main"
description:
name: dio_cookie_manager
sha256: ed7ee3ba6cdb54599c8984d5a4ce09675c553ead6c28608eb54e38eec5b4f954
sha256: c4b7a693aa09efd694a5c5e12065daa5e026647b106245281ed1042b3ebefb8f
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
version: "3.1.0"
fake_async:
dependency: transitive
description:
@ -317,14 +317,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.2"
package_info:
package_info_plus:
dependency: "direct main"
description:
name: package_info
sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75"
name: package_info_plus
sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
version: "4.0.2"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
path:
dependency: transitive
description:
@ -594,6 +602,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.2"
universal_io:
dependency: transitive
description:
name: universal_io
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.2"
uuid:
dependency: transitive
description:

View File

@ -46,9 +46,9 @@ dependencies:
flutter_screenutil: ^5.7.0
# http
dio: ^4.0.0
dio_cookie_manager: ^2.0.0
cookie_jar: ^3.0.1
dio: ^5.2.1+1
dio_cookie_manager: ^3.1.0
cookie_jar: ^4.0.5
# 日期
intl: ^0.18.0
@ -80,7 +80,7 @@ dependencies:
device_info: ^2.0.0
# 包信息
package_info: ^2.0.0
package_info_plus: ^4.0.2
# 路径查询
path_provider: ^2.0.1