推送配置,测试

This commit is contained in:
2025-12-31 17:22:13 +08:00
parent 6629c8047f
commit 295b71c819
15 changed files with 557 additions and 76 deletions

View File

@@ -7,11 +7,14 @@ class AppTheme {
static const Color themeColor = Color(0xFF0c83c3);
static const String test_service_url = "http://47.100.49.118:8090/api/";
//http://192.168.110.222:8080/
static const String test_service_url = "https://beta-esg.api.lnh2e.com/";
static const String release_service_url = "";
//加氢站相关查询
static const String jiaqing_service_url = "https://lnh2e.com/api/lingniu-manager-v1/v1/";
static const String jiaqing_service_url =
"https://beta.lnh2e.com/api/lingniu-manager-v1/v1/";
//车辆信息
static const String car_service_url = "http://47.99.166.38:20000/";
@@ -56,12 +59,9 @@ class AppTheme {
appBarTheme: const AppBarTheme(
backgroundColor: Color.fromARGB(255, 34, 34, 34),
centerTitle: true,
titleTextStyle: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
titleTextStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
bottomAppBarTheme: BottomAppBarThemeData(
bottomAppBarTheme: BottomAppBarThemeData(
color: Color.fromARGB(255, 34, 34, 34),
elevation: 4.0,
),

View File

@@ -14,7 +14,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
WidgetsBinding widgetsBinding = await init(
isDebug: false,
isDebug: true,
logTag: '小羚羚',
supportedLocales: [Locale('zh', 'CN')],
);
@@ -30,7 +30,7 @@ void main() async {
// 设计稿尺寸 单位dp
designSize: const Size(390, 844),
// Getx Log
enableLog: false,
enableLog: true,
// 默认的跳转动画
defaultTransition: Transition.rightToLeft,
// 主题模式
@@ -76,6 +76,8 @@ void initHttpSet() {
await StorageService.to.clearLoginInfo();
Get.offAll(() => LoginPage());
return baseModel.message;
}else {
return "服务繁忙,稍后重试";
}
} on Exception catch (e) {
e.printInfo();

View File

@@ -1,3 +1,6 @@
import 'dart:io';
import 'package:aliyun_push_flutter/aliyun_push_flutter.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:getx_scaffold/getx_scaffold.dart';
import 'package:ln_jq_app/pages/b_page/base_widgets/view.dart';
@@ -12,14 +15,115 @@ class HomeController extends GetxController with BaseControllerMixin {
HomeController();
final _aliyunPush = AliyunPushFlutter();
@override
void onInit() {
super.onInit();
initAliyunPush();
addPushCallback();
FlutterNativeSplash.remove();
}
void addPushCallback() {
_aliyunPush.addMessageReceiver(
onNotification: _onNotification,
onNotificationOpened: _onNotificationOpened,
onNotificationRemoved: _onNotificationRemoved,
onMessage: _onMessage,
onAndroidNotificationReceivedInApp: _onAndroidNotificationReceivedInApp,
onAndroidNotificationClickedWithNoAction: _onAndroidNotificationClickedWithNoAction,
onIOSChannelOpened: _onIOSChannelOpened,
onIOSRegisterDeviceTokenSuccess: _onIOSRegisterDeviceTokenSuccess,
onIOSRegisterDeviceTokenFailed: _onIOSRegisterDeviceTokenFailed,
);
}
Future<void> _onAndroidNotificationClickedWithNoAction(
Map<dynamic, dynamic> message,
) async {
Logger.d('onAndroidNotificationClickedWithNoAction ====> $message');
}
Future<void> _onAndroidNotificationReceivedInApp(Map<dynamic, dynamic> message) async {
Logger.d('onAndroidNotificationReceivedInApp ====> $message');
}
Future<void> _onMessage(Map<dynamic, dynamic> message) async {
Logger.d('onMessage ====> $message');
}
Future<void> _onNotification(Map<dynamic, dynamic> message) async {
Logger.d('onNotification ====> $message');
}
Future<void> _onNotificationOpened(Map<dynamic, dynamic> message) async {
Logger.d('onNotificationOpened ====> $message');
}
Future<void> _onNotificationRemoved(Map<dynamic, dynamic> message) async {
Logger.d('onNotificationRemoved ====> $message');
}
Future<void> _onIOSChannelOpened(Map<dynamic, dynamic> message) async {
Logger.d('onIOSChannelOpened ====> $message');
}
Future<void> _onIOSRegisterDeviceTokenSuccess(Map<dynamic, dynamic> message) async {
Logger.d('onIOSRegisterDeviceTokenSuccess ====> $message');
}
Future<void> _onIOSRegisterDeviceTokenFailed(Map<dynamic, dynamic> message) async {
Logger.d('onIOSRegisterDeviceTokenFailed====> $message');
}
Future<void> initAliyunPush() async {
String appKey;
String appSecret;
if (Platform.isIOS) {
appKey = '335642649';
appSecret = '173bc08bd5df422da20c8e3ffbf0521b';
} else {
appKey = "335642645";
appSecret = "39628204345a4240b5b645b68a5896c7";
}
var result = await _aliyunPush.initPush(appKey: appKey, appSecret: appSecret);
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Logger.d('初始化推送成功');
if(Platform.isIOS){
var result = await _aliyunPush.showIOSNoticeWhenForeground(true);
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Logger.d('设置前台显示通知成功');
} else {
Logger.d('设置前台显示通知失败');
}
}else if(Platform.isAndroid){
await _aliyunPush.setNotificationInGroup(true);
var result = await _aliyunPush.createAndroidChannel(
"xll_push_android", '新消息通知', 2, '收到新消息的通知类别');
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Logger.d('创建通道成功');
} else {
var errorCode = result['code'];
var errorMsg = result['errorMsg'];
Logger.d('创建通道失败, $errorCode - $errorMsg');
}
}
} else {
var errorMsg = result['errorMsg'];
Logger.d('初始化推送失败: $code - $errorMsg');
}
}
// 根据登录状态和登录渠道返回不同的首页
Widget getHomePage() {
requestPermission();
//登录状态跳转
if (StorageService.to.isLoggedIn) {
// 如果已登录,再判断是哪个渠道
@@ -35,4 +139,25 @@ class HomeController extends GetxController with BaseControllerMixin {
return LoginPage();
}
}
void requestPermission() async {
PermissionStatus status = await Permission.notification.status;
if (status.isGranted) {
Logger.d("通知权限已开启");
return;
}
if (status.isDenied) {
// 建议此处增加一个应用内的 Rationale (解释说明) 弹窗
status = await Permission.notification.request();
}
if (status.isGranted) {
// 授权成功
Logger.d('通知已开启');
} else if (status.isPermanentlyDenied) {
Logger.d('通知权限已被拒绝,请到系统设置中开启');
} else if (status.isDenied) {
Logger.d('请授予通知权限,以便接收加氢站通知');
}
}
}

View File

@@ -1,3 +1,4 @@
import 'package:aliyun_push_flutter/aliyun_push_flutter.dart';
import 'package:flutter/material.dart';
import 'package:getx_scaffold/getx_scaffold.dart';
import 'package:ln_jq_app/common/login_util.dart';
@@ -21,8 +22,10 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
bool cLogin = true;
bool _obscureText = true;
// 用于管理“记住密码”的复选框状态
bool _rememberPassword = true;
// 用于确保凭证只在首次加载时回填一次
bool _credentialsLoaded = false;
@@ -198,20 +201,24 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
phone: phone,
);
//注册推送别名
addAlias(phone);
//登录后查询已绑定车辆信息
var carInfo = await HttpService.to.get(
"appointment/driver/getTruckInfoByDriver?phone=$phone"
"appointment/driver/getTruckInfoByDriver?phone=$phone",
);
if (carInfo != null) {
var carInforesult = BaseModel.fromJson(carInfo.data);
if (carInforesult.data != null) {
final vehicle = VehicleInfo.fromJson(carInforesult.data as Map<String, dynamic>);
final vehicle = VehicleInfo.fromJson(
carInforesult.data as Map<String, dynamic>,
);
//保存使用
await StorageService.to.saveVehicleInfo(vehicle);
}
}
//页面操作
dismissLoading();
showToast('登录成功,欢迎您');
@@ -269,9 +276,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
hintText: '请输入密码',
border: OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(
_obscureText ? Icons.visibility_off : Icons.visibility,
),
icon: Icon(_obscureText ? Icons.visibility_off : Icons.visibility),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
@@ -304,7 +309,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
GestureDetector(
onTap: () => setState(() => _rememberPassword = !_rememberPassword),
child: const Text('记住密码', style: TextStyle(color: Colors.grey)),
)
),
],
),
SizedBox(height: 20), // 调整间距
@@ -317,7 +322,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
onPressed: () async {
String account = controller.stationIdController.text;
String password = controller.passwordController.text;
if (account.isEmpty || password.isEmpty) {
showToast("请输入账号和密码");
return;
@@ -353,13 +358,18 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
String token = result.data['token'] ?? '';
String userId = result.data['userId'] ?? '';
String mobile = result.data['mobile'] ?? '';
await StorageService.to.saveLoginInfo(
token: token,
userId: userId,
phone: mobile,
channel: "station",
);
//注册推送别名
addAlias(mobile);
// 根据复选框状态保存或清除密码 ---
if (_rememberPassword) {
await StorageService.to.saveStationCredentials(account, password);
@@ -384,6 +394,20 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
);
}
final _aliyunPush = AliyunPushFlutter();
void addAlias(String alias) async {
var result = await _aliyunPush.addAlias(alias);
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Logger.d('添加别名$alias成功');
} else {
var errorCode = result['code'];
var errorMsg = result['errorMsg'];
Logger.d('添加别名$alias失败: $errorCode - $errorMsg');
}
}
@override
Widget build(BuildContext context) {
return GetBuilder<LoginController>(

View File

@@ -1,12 +1,14 @@
import 'package:aliyun_push_flutter/aliyun_push_flutter.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:getx_scaffold/common/utils/log_util.dart';
import 'package:ln_jq_app/common/model/vehicle_info.dart';
/// 定义登录渠道的枚举类型
enum LoginChannel {
station, // 站点
driver, // 司机
none, // 未登录或未知
driver, // 司机
none, // 未登录或未知
}
class StorageService extends GetxService {
@@ -22,10 +24,10 @@ class StorageService extends GetxService {
static const String _vehicleInfoKey = 'vehicle_info';
static const String _stationAccountKey = 'station_account';
static const String _stationPasswordKey = 'station_password';
// 新增:用于标记“绑定车辆”弹窗是否已在本会话中显示过
static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown';
static StorageService get to => Get.find();
Future<StorageService> init() async {
@@ -33,22 +35,28 @@ class StorageService extends GetxService {
return this;
}
// --- Getters ---
// --- Getters ---
bool get isLoggedIn => _box.read<String?>(_tokenKey)?.isNotEmpty ?? false;
String? get token => _box.read<String?>(_tokenKey);
String? get userId => _box.read<String?>(_userIdKey);
String? get name => _box.read<String?>(_nameKey);
String? get phone => _box.read<String?>(_phoneKey);
String? get idCard => _box.read<String?>(_idCardKey);
bool get hasVehicleInfo => _box.hasData(_vehicleInfoKey);
String? get stationAccount => _box.read<String?>(_stationAccountKey);
String? get stationPassword => _box.read<String?>(_stationPasswordKey);
// 新增:获取“绑定车辆”弹窗是否已显示的标志
bool get hasShownBindVehicleDialog => _box.read<bool>(_bindDialogShownKey) ?? false;
VehicleInfo? get vehicleInfo {
final vehicleJson = _box.read<String?>(_vehicleInfoKey);
if (vehicleJson != null) {
@@ -98,7 +106,6 @@ class StorageService extends GetxService {
await _box.write(_bindDialogShownKey, true);
}
Future<void> clearVehicleInfo() async {
await _box.remove(_vehicleInfoKey);
}
@@ -118,5 +125,22 @@ class StorageService extends GetxService {
await clearVehicleInfo();
// 登出时,清除“绑定车辆”弹窗的显示记录,以便下次登录时可以再次弹出
await _box.remove(_bindDialogShownKey);
delAlias();
}
final _aliyunPush = AliyunPushFlutter();
void delAlias() async {
String phoen = StorageService.to.phone ?? "";
var result = await _aliyunPush.removeAlias(phoen);
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Logger.d('删除别名$phoen成功');
} else {
var errorCode = result['code'];
var errorMsg = result['errorMsg'];
Logger.d('删除别名$phoen失败: $errorCode - $errorMsg');
}
}
}