Bläddra i källkod

Merge remote-tracking branch 'refs/remotes/origin/v1.1.5' into v1.1.5-iOS

# Conflicts:
#	pubspec.lock
zk 5 månader sedan
förälder
incheckning
2262ea2083

+ 4 - 0
assets/string/base/string.xml

@@ -393,4 +393,8 @@
     <string name="member_activity_countdown">优惠活动倒计时</string>
     <string name="member_activity_specially_preferential">限时特惠</string>
     <string name="member_activity_to_buy">去使用</string>
+    <string name="member_ios_pay_desc">
+        1.订阅后会从您的iunes账户中扣除相关费用。如需取消续订,请在当前订阅周期结束前,至少24小时内通过手机“账户设置”的订阅管理关闭自动续费功能。
+        \n2.未成年人请在监护者的陪同下进行购买。 \n3.购买后不支持退款,请仔细审阅《隐私权政策》《用户协议》和《会员协议》。
+    </string>
 </resources>

+ 5 - 0
lib/data/bean/goods_bean.dart

@@ -28,6 +28,9 @@ class GoodsBean {
   @JsonKey(name: 'subscriptionMillis')
   int subscriptionMillis;
 
+  @JsonKey(name: 'subscribable')
+  int subscribable;
+
   @JsonKey(name: 'popular')
   bool popular;
 
@@ -45,6 +48,7 @@ class GoodsBean {
       this.name,
       this.level,
       this.originalAmount,
+      this.subscribable,
       this.amount,
       this.subscriptionMillis,
       this.popular,
@@ -61,6 +65,7 @@ class GoodsBean {
       name,
       level,
       originalAmount,
+      subscribable,
       amount,
       subscriptionMillis,
       popular,

+ 2 - 0
lib/data/bean/goods_bean.g.dart

@@ -11,6 +11,7 @@ GoodsBean _$GoodsBeanFromJson(Map<String, dynamic> json) => GoodsBean(
       json['name'] as String,
       (json['level'] as num).toInt(),
       (json['originalAmount'] as num).toInt(),
+      (json['subscribable'] as num).toInt(),
       (json['amount'] as num).toInt(),
       (json['subscriptionMillis'] as num).toInt(),
       json['popular'] as bool,
@@ -30,6 +31,7 @@ Map<String, dynamic> _$GoodsBeanToJson(GoodsBean instance) => <String, dynamic>{
       'originalAmount': instance.originalAmount,
       'amount': instance.amount,
       'subscriptionMillis': instance.subscriptionMillis,
+      'subscribable': instance.subscribable,
       'popular': instance.popular,
       'newcomer': instance.newcomer,
       'tag': instance.tag,

+ 5 - 0
lib/data/repositories/account_repository.dart

@@ -19,6 +19,7 @@ import 'package:location/di/get_it.dart';
 import 'package:location/module/main/today_track_helper.dart';
 import 'package:location/push_notification/ios_push_notification_service.dart';
 import 'package:location/resource/string.gen.dart';
+import 'package:location/sdk/gravity/gravity_helper.dart';
 import 'package:location/socket/atmob_location_client.dart';
 import 'package:location/utils/async_util.dart';
 import 'package:location/utils/atmob_log.dart';
@@ -144,6 +145,8 @@ class AccountRepository {
     phoneEventRepository.startReportPhoneEvent();
 
     TodayTrackHelper.getInstance().clear();
+
+    GravityHelper.onLogin();
   }
 
   void logout() {
@@ -165,6 +168,8 @@ class AccountRepository {
     urgentContactRepository.clearContactList();
 
     phoneEventRepository.stopReportPhoneEvent();
+
+    GravityHelper.onLogout();
   }
 
   void refreshMemberStatus() {

+ 1 - 0
lib/data/repositories/member_repository.dart

@@ -114,6 +114,7 @@ class MemberRepository {
         .then(HttpHandler.handle(false))
         .then((data) {
       if (data.payStatus == PaymentStatus.payStatusSuccess) {
+        clearLastSelectedMember();
         accountRepository.refreshMemberStatus();
       }
       return data.payStatus;

+ 0 - 1
lib/helper/member_pay_helper.dart

@@ -234,7 +234,6 @@ class MemberPayHelper implements PaymentStatusCallback {
       String orderNo, PayItemBean paymentWay, GoodsBean storeItemBean) {
     ///购买成功消失
     LoadingDialog.hide();
-    memberRepository.clearLastSelectedMember();
 
     ///购买成功之后弹出
     onPaySucessShow();

+ 6 - 5
lib/main.dart

@@ -41,16 +41,17 @@ void main() {
     //非隐私相关
     initCommon();
 
-    runApp(const MyApp());
-
-    //隐私相关:系统参数&第三方sdk初始化
-    await PrivacyCompliance.ensurePolicyGranted(AppInitTask());
-
     ///实现推送
     if (Platform.isIOS) {
+      // ⚠️ 必须在 runApp 前
       initPushNotification();
     }
 
+    runApp(const MyApp());
+
+    //隐私相关:系统参数&第三方sdk初始化
+    await PrivacyCompliance.ensurePolicyGranted(AppInitTask());
+
     //檢查地址
     checkEnv();
   });

+ 1 - 14
lib/module/main/main_controller.dart

@@ -93,7 +93,6 @@ class MainController extends BaseController {
 
   DateTime? _lastPressedAt;
   DateTime? _lastRequestFavor;
-  bool isFirstShowMemberPage = true;
   String? lastCheckFriendId;
   bool isExecuteAutoSelect = false;
 
@@ -121,6 +120,7 @@ class MainController extends BaseController {
   @override
   void onReady() {
     super.onReady();
+    MapHelper.checkPermissionStartLocation();
     InternetConnectionHelper.getInstance().startInternetConnection();
     InternetConnectionHelper.getInstance().startListenNetwork();
 
@@ -160,11 +160,9 @@ class MainController extends BaseController {
       _updateMineLocation(location);
     });
 
-    _isShowAppStartMemberPage(accountRepository.memberStatusInfo.value);
     //根据会员状态刷新好友列表
     memberStatusInfoSubscription =
         accountRepository.memberStatusInfo.listen((memberStatus) {
-      _isShowAppStartMemberPage(memberStatus);
       if (memberStatus != null) {
         _updateFriendList(_friendsList);
       }
@@ -174,17 +172,6 @@ class MainController extends BaseController {
     _refreshTrackDailyDialogs();
   }
 
-  void _isShowAppStartMemberPage(MemberStatusInfo? memberInfo) async {
-    if (memberInfo == null) {
-      return;
-    }
-    if (memberInfo.expired && isFirstShowMemberPage == true ||
-        !accountRepository.isLogin.value) {
-      isFirstShowMemberPage = false;
-      await Future.delayed(Duration(milliseconds: 300));
-      MemberPage.start(enterTyp: MemberPageType.activity);
-    }
-  }
 
   void _updateMineLocation(LocationInfo? location) {
     final mineInfo = accountRepository.mineUserInfo.value;

+ 6 - 1
lib/module/member/activity/member_activity_controller.dart

@@ -21,6 +21,7 @@ import '../../../resource/string.gen.dart';
 import '../../../utils/async_util.dart';
 import '../../../utils/toast_util.dart';
 import '../../browser/browser_view.dart';
+import '../../main/main_page.dart';
 
 @injectable
 class MemberActivityController extends BaseController {
@@ -94,7 +95,11 @@ class MemberActivityController extends BaseController {
   }
 
   void onBack() {
-    Get.back();
+    if (Get.key.currentState?.canPop() == true) {
+      Get.back();
+    } else {
+      MainPage.start();
+    }
   }
 
   void onBuyClick() {

+ 21 - 8
lib/module/member/activity/member_activity_page.dart

@@ -25,8 +25,12 @@ import 'member_activity_controller.dart';
 class MemberActivityPage extends BasePage<MemberActivityController> {
   const MemberActivityPage({super.key});
 
-  static void start() {
-    Get.toNamed(RoutePath.memberActivity);
+  static void start({bool isOffAll = false}) {
+    if (isOffAll) {
+      Get.offAllNamed(RoutePath.memberActivity);
+    } else {
+      Get.toNamed(RoutePath.memberActivity);
+    }
   }
 
   @override
@@ -41,12 +45,21 @@ class MemberActivityPage extends BasePage<MemberActivityController> {
 
   @override
   Widget buildBody(BuildContext context) {
-    return Stack(
-      children: [
-        buildActivityContent(),
-        buildToolbar(),
-        buildMemberBottomView()
-      ],
+    return PopScope(
+      canPop: false,
+      onPopInvokedWithResult: (bool didPop, dynamic result) {
+        if (didPop) {
+          return;
+        }
+        controller.onBack();
+      },
+      child: Stack(
+        children: [
+          buildActivityContent(),
+          buildToolbar(),
+          buildMemberBottomView()
+        ],
+      ),
     );
   }
 

+ 19 - 1
lib/module/member/member_controller.dart

@@ -53,6 +53,10 @@ class MemberController extends BaseController implements PaymentStatusCallback {
   final MemberRepository memberRepository;
   final PaymentStatusManager paymentStatusManager;
 
+  final RxBool _isShowMemberSubscribeTxt = false.obs;
+
+  bool get isShowMemberSubscribeTxt => _isShowMemberSubscribeTxt.value;
+
   final switcherController = SwitcherController();
 
   final ScrollController scrollController = ScrollController();
@@ -246,6 +250,7 @@ class MemberController extends BaseController implements PaymentStatusCallback {
       payItemList.clear();
       evaluateList.clear();
       _selectedGoods.value = null;
+      _checkMemberHasSubscribe(response.goodsList);
       if (response.goodsList?.isNotEmpty == true) {
         goodsList.addAll(response.goodsList!);
         _selectedGoods.value = goodsList.first;
@@ -260,6 +265,20 @@ class MemberController extends BaseController implements PaymentStatusCallback {
     });
   }
 
+  void _checkMemberHasSubscribe(List<GoodsBean>? goodsList) {
+    if (goodsList == null) {
+      _isShowMemberSubscribeTxt.value = false;
+      return;
+    }
+    for (var goods in goodsList) {
+      if (goods.subscribable == 1) {
+        _isShowMemberSubscribeTxt.value = true;
+        return;
+      }
+    }
+    _isShowMemberSubscribeTxt.value = false;
+  }
+
   void onGoodsItemClick(GoodsBean item) {
     _selectedGoods.value = item;
     onBuyClick();
@@ -621,7 +640,6 @@ class MemberController extends BaseController implements PaymentStatusCallback {
       String orderNo, PayItemBean paymentWay, GoodsBean storeItemBean) {
     ///购买成功消失
     LoadingDialog.hide();
-    memberRepository.clearLastSelectedMember();
 
     ///购买成功之后弹出
     afterTheFirstPurchasePromptSharingBoxPops();

+ 18 - 1
lib/module/member/member_page.dart

@@ -65,7 +65,7 @@ class MemberPage extends BasePage<MemberController> {
 
   @override
   bool statusBarDarkFont() {
-    return false;
+    return true;
   }
 
   @override
@@ -153,6 +153,22 @@ class MemberPage extends BasePage<MemberController> {
                             ),
                             //SizedBox(height: 8.w),
                             buildUserEvaluateList(),
+                            Obx(() {
+                              return Visibility(
+                                  visible:
+                                      controller.isShowMemberSubscribeTxt &&
+                                          Platform.isIOS,
+                                  child: Padding(
+                                    padding: EdgeInsets.only(
+                                        left: 16.w, right: 16.w, top: 16.w),
+                                    child: Text(
+                                      StringName.memberIosPayDesc,
+                                      style: TextStyle(
+                                          fontSize: 10.sp,
+                                          color: ColorName.black60),
+                                    ),
+                                  ));
+                            }),
                             SizedBox(
                                 height: 190.w +
                                     MediaQuery.of(Get.context!).padding.bottom)
@@ -902,6 +918,7 @@ class MemberPage extends BasePage<MemberController> {
           ),
           SizedBox(height: 20.w),
           Visibility(
+            visible: !isLast,
             child: Container(
               color: '#EEEEEE'.color,
               height: 1.w,

+ 50 - 4
lib/module/splash/splash_controller.dart

@@ -5,33 +5,79 @@ import 'package:flutter/services.dart';
 import 'package:get/get_utils/src/platform/platform.dart';
 import 'package:injectable/injectable.dart';
 import 'package:location/base/base_controller.dart';
+import 'package:location/data/api/response/member_status_response.dart';
+import 'package:location/data/repositories/account_repository.dart';
 import 'package:location/dialog/agreement_dialog.dart';
 import 'package:location/module/main/main_page.dart';
+import 'package:location/module/member/activity/member_activity_page.dart';
 import 'package:location/sdk/umeng/umeng_helper.dart';
+import 'package:location/utils/date_util.dart';
 
+import '../../data/consts/error_code.dart';
+import '../../utils/async_util.dart';
+import '../../utils/http_handler.dart';
 import '../../utils/privacy_compliance.dart';
 
 @injectable
 class SplashController extends BaseController {
   final splashDelayedTime = 2;
 
+  DateTime? splashStartTime;
+
+  SplashController();
+
   @override
   void onReady() {
     final isAgreePrivacy = PrivacyCompliance.isAgreePrivacyPolicy();
     if (isAgreePrivacy) {
-      isAgreePrivacyNextStep(splashDelayedTime);
+      _doSplashTask();
     } else {
       AgreementDialog.show(cancelClick: () {
         exitApp();
       }, sureClick: () async {
         await _agreePrivacy();
-        isAgreePrivacyNextStep(0);
+        _doSplashTask();
       });
     }
   }
 
-  void isAgreePrivacyNextStep(int splashDelayedTime) {
-    _goMain(Duration(seconds: splashDelayedTime));
+  void _doSplashTask() async {
+    //获取用户会员信息
+    splashStartTime = DateUtil.getNow();
+    AsyncUtil.retry(() => AccountRepository.getInstance().getMemberStatus(),
+        Duration(seconds: 1), timeout: Duration(seconds: 6), maxRetry: 6,
+        predicate: (error) {
+      if (error is ServerErrorException) {
+        return error.code != ErrorCode.noLoginError;
+      }
+      return true;
+    }).then((info) {
+      _memberCheckNextStep(response: info);
+    }).catchError((error) {
+      _memberCheckNextStep();
+    });
+  }
+
+  void _memberCheckNextStep({MemberStatusResponse? response}) {
+    final endTime = DateUtil.getNow();
+    final duration = endTime.difference(splashStartTime!);
+    final splashDelayedTime = this.splashDelayedTime * 1000;
+
+    final int remainTimeMilliseconds =
+        duration.inMilliseconds < splashDelayedTime
+            ? splashDelayedTime - duration.inMilliseconds
+            : 0;
+    if (response != null && !response.expired) {
+      _goMain(Duration(milliseconds: remainTimeMilliseconds));
+    } else {
+      _goMemberActivity(Duration(milliseconds: remainTimeMilliseconds));
+    }
+  }
+
+  void _goMemberActivity(Duration delayTime) {
+    Timer(delayTime, () {
+      MemberActivityPage.start(isOffAll: true);
+    });
   }
 
   void _goMain(Duration delayTime, {Map<String, dynamic>? arguments}) {

+ 4 - 0
lib/resource/string.gen.dart

@@ -331,6 +331,8 @@ class StringName {
   static String get memberActivitySpeciallyPreferential =>
       'member_activity_specially_preferential'.tr; // 限时特惠
   static String get memberActivityToBuy => 'member_activity_to_buy'.tr; // 去使用
+  static String get memberIosPayDesc => 'member_ios_pay_desc'
+      .tr; // 1.订阅后会从您的iunes账户中扣除相关费用。如需取消续订,请在当前订阅周期结束前,至少24小时内通过手机“账户设置”的订阅管理关闭自动续费功能。 \n2.未成年人请在监护者的陪同下进行购买。 \n3.购买后不支持退款,请仔细审阅《隐私权政策》《用户协议》和《会员协议》。
 }
 class StringMultiSource {
   StringMultiSource._();
@@ -661,6 +663,8 @@ class StringMultiSource {
       'member_activity_countdown': '优惠活动倒计时',
       'member_activity_specially_preferential': '限时特惠',
       'member_activity_to_buy': '去使用',
+      'member_ios_pay_desc':
+          '1.订阅后会从您的iunes账户中扣除相关费用。如需取消续订,请在当前订阅周期结束前,至少24小时内通过手机“账户设置”的订阅管理关闭自动续费功能。 \n2.未成年人请在监护者的陪同下进行购买。 \n3.购买后不支持退款,请仔细审阅《隐私权政策》《用户协议》和《会员协议》。',
     },
   };
 }

+ 10 - 1
lib/sdk/gravity/gravity_helper.dart

@@ -6,6 +6,7 @@ import 'package:gravity_engine/gravity_engine_method_channel.dart';
 import 'package:location/data/repositories/account_repository.dart';
 import 'package:location/data/repositories/config_repository.dart';
 import 'package:location/utils/atmob_log.dart';
+import 'package:location/utils/toast_util.dart';
 import '../../data/api/response/member_status_response.dart';
 import '../../data/consts/build_config.dart';
 import '../../data/consts/payment_type.dart';
@@ -18,6 +19,7 @@ typedef GravitySuccessCallback = void Function();
 class GravityHelper {
   static const String tag = 'GravityHelper';
   static const String _keyCurrentDeviceId = "current_device_id";
+  static const bool _isShowToast = false;
   static CancelableFuture<bool>? _initFuture;
   static String? _currentClientId;
 
@@ -82,13 +84,20 @@ class GravityHelper {
               atmobPlatformInfo.channelName ?? '',
               BuildConfig.isDebug)
           .then((data) {
-        debugPrint('gravity initialize($deviceId) success');
+        _toast('gravity initialize success clientId:$deviceId');
+        debugPrint('gravity initialize success clientId:$deviceId');
         GravityHelper._currentClientId = deviceId;
         return data;
       });
     }, 5);
   }
 
+  static void _toast(String msg) {
+    if (_isShowToast) {
+      ToastUtil.show(msg);
+    }
+  }
+
   static void onLogin() {
     _clearCurrentDeviceId();
     _initialize(true, callback: () {

+ 8 - 1
lib/sdk/map/map_helper.dart

@@ -1,5 +1,6 @@
 import 'package:flutter_map/flutter_map.dart';
 import 'package:location/socket/atmob_location_client.dart';
+import 'package:location/utils/permission_util.dart';
 import '../../utils/atmob_log.dart';
 
 class MapHelper {
@@ -13,7 +14,7 @@ class MapHelper {
 
   static Future<void> init() async {
     await FlutterMap.init();
-    _initLocationClient(); 
+    _initLocationClient();
   }
 
   static void _initLocationClient() {
@@ -39,6 +40,12 @@ class MapHelper {
     return FlutterMap.startLocation();
   }
 
+  static Future<void> checkPermissionStartLocation() async {
+    if (await PermissionUtil.checkLocationPermission()) {
+      startLocation();
+    }
+  }
+
   static MapLocation? getLastLocation() {
     return _lastLocation;
   }

+ 1 - 1
plugins/map/lib/src/core/flutter_map.dart

@@ -13,7 +13,7 @@ class FlutterMap {
     }
     MethodChannel channel = const MethodChannel(MapConstants.mapMethodChannel);
 
-    MapPlatform mapPlatform = MapPlatform(channel);
+    MapPlatform mapPlatform = MapPlatformImpl(channel);
     if (!await mapPlatform.init()) {
       throw Exception("地图初始化失败,未找到适配的地图,请检查是否添加地图库");
     }

+ 9 - 1
plugins/map/lib/src/core/map_controller.dart

@@ -15,12 +15,19 @@ import 'package:flutter_map/src/interface/map_marker_interface.dart';
 import 'package:flutter_map/src/interface/map_polyline_interface.dart';
 import '../entity/map_padding.dart';
 
-class MapController
+abstract class MapBaseController
     implements MapMarkerInterface, MapFunInterface, MapPolylineInterface {
+  void setChannel(MethodChannel channel);
+
+  void dispose();
+}
+
+class MapController implements MapBaseController {
   final _pendingOperations = <Map<String, dynamic>>[];
   MethodChannel? _channel;
   bool _isDisposed = false;
 
+  @override
   void setChannel(MethodChannel channel) {
     if (_isDisposed) return;
 
@@ -37,6 +44,7 @@ class MapController
     });
   }
 
+  @override
   void dispose() {
     _isDisposed = true;
     _pendingOperations.clear();

+ 4 - 2
plugins/map/lib/src/core/map_platform.dart

@@ -4,13 +4,15 @@ import 'package:flutter/services.dart';
 import 'package:flutter_map/src/interface/map_trace_interface.dart';
 import '../../flutter_map.dart';
 
-class MapPlatform implements MapSDKInterface, MapTraceInterface {
+abstract class MapPlatform implements MapSDKInterface, MapTraceInterface {}
+
+class MapPlatformImpl implements MapPlatform {
   final MethodChannel _channel;
 
   final EventChannel _eventChannel =
       const EventChannel(MapConstants.mapLocationEventChannel);
 
-  MapPlatform(this._channel);
+  MapPlatformImpl(this._channel);
 
   @override
   Future<String?> getPlatformName() {

+ 1 - 1
plugins/map/lib/src/entity/map_location.dart

@@ -61,6 +61,6 @@ class MapLocation implements Codable {
 
   @override
   String toString() {
-    return 'MapLocation{time: $time, address: $address, latitude: $latitude, longitude: $longitude, errorCode: $errorCode, speed: $speed, bearing: $bearing}';
+    return '{time: $time, address: $address, latitude: $latitude, longitude: $longitude, errorCode: $errorCode, speed: $speed, bearing: $bearing}';
   }
 }

+ 1 - 1
plugins/map/lib/src/widget/map_widget.dart

@@ -14,7 +14,7 @@ import '../../flutter_map.dart';
 import '../entity/polyline.dart';
 
 class MapWidget extends StatefulWidget {
-  final MapController? controller;
+  final MapBaseController? controller;
   final MarkerTapCallback? onMarkerTap;
   final List<Marker>? markers;
   final List<Polyline>? polyline;

+ 2 - 2
plugins/map_amap_android/android/src/main/java/com/atmob/map_amap_android/FlutterLocationEventPlugin.java

@@ -36,7 +36,7 @@ public class FlutterLocationEventPlugin implements FlutterPlugin, EventChannel.S
         AMapHelper.removeOnLocationListener(this);
         eventChannel = null;
         eventSink = null;
-        locationMap.clear();
+        if (locationMap != null) locationMap.clear();
         locationMap = null;
     }
 
@@ -48,7 +48,7 @@ public class FlutterLocationEventPlugin implements FlutterPlugin, EventChannel.S
     @Override
     public void onCancel(Object o) {
         eventSink = null;
-        locationMap.clear();
+        if (locationMap != null) locationMap.clear();
         locationMap = null;
     }
 

+ 22 - 36
plugins/map_amap_android/android/src/main/java/com/atmob/map_amap_android/util/AMapHelper.java

@@ -24,11 +24,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 public class AMapHelper {
     private static final String TAG = "AMapHelper";
-    public static final String KEY_LAST_TRACK_ID = "amap_last_track_id";
     private static final int AMAP_NOTIFICATION_ID = 350;
     private static final String AMAP_NOTIFICATION_CHANNEL_ID = "amap_notification_channel_id";
     private static final String AMAP_NOTIFICATION_CHANNEL_NAME = "Location Tracking";
-    private static final AtomicBoolean isLocationInit = new AtomicBoolean(false);
     private static final ArrayList<OnLocationListener> locationListeners = new ArrayList<>();
     private static AMapLocation lastLocation;
     @SuppressLint("StaticFieldLeak")
@@ -38,48 +36,36 @@ public class AMapHelper {
             Manifest.permission.ACCESS_COARSE_LOCATION
     };
 
-    public static void init(Context context) {
-        if (ProcessUtil.isMainProcess(context)) {
-            initLocation(context);
-        }
-    }
-
-    private static void initLocation(Context context) {
-        if (isLocationInit.compareAndSet(false, true)) {
-            try {
-                LogUtil.d(TAG, "amap ... initLocation...");
-                AMapLocationClient.updatePrivacyShow(context, true, true);
-                AMapLocationClient.updatePrivacyAgree(context, true);
-                aMapLocationClient = new AMapLocationClient(context);
-                aMapLocationClient.setLocationOption(new AMapLocationClientOption().setInterval(5000));
-                aMapLocationClient.setLocationListener(aMapLocation -> {
-                    if (aMapLocation != null) {
-                        if (aMapLocation.getErrorCode() == 0) {
-                            lastLocation = aMapLocation;
-                            LogUtil.d(TAG, "onLocationChanged: " + aMapLocation);
-                            for (OnLocationListener locationListener : locationListeners) {
-                                locationListener.onLocationChanged(aMapLocation);
-                            }
-                        }
+    public static void init(Context context) throws Exception {
+        LogUtil.d(TAG, "amap ... initLocation...");
+        AMapLocationClient.updatePrivacyShow(context, true, true);
+        AMapLocationClient.updatePrivacyAgree(context, true);
+        aMapLocationClient = new AMapLocationClient(context);
+        aMapLocationClient.setLocationOption(new AMapLocationClientOption().setInterval(5000));
+        aMapLocationClient.setLocationListener(aMapLocation -> {
+            if (aMapLocation != null) {
+                if (aMapLocation.getErrorCode() == 0) {
+                    lastLocation = aMapLocation;
+                    LogUtil.d(TAG, "onLocationChanged: " + aMapLocation);
+                    for (OnLocationListener locationListener : locationListeners) {
+                        locationListener.onLocationChanged(aMapLocation);
                     }
-                });
-                if (PermissionUtil.hasPermission(context, LOCATION_PERMISSION)) {
-                    aMapLocationClient.startLocation();
-                    aMapLocationClient.enableBackgroundLocation(AMAP_NOTIFICATION_ID, createLocationNotification(context));
                 }
-            } catch (Exception e) {
-                isLocationInit.set(false);
-                LogUtil.e(TAG, "initLocation failed.", e);
             }
-        }
+        });
     }
 
     public static void startLocation(Context context) {
-        if (isLocationInit.get()) {
+        if (aMapLocationClient == null) {
+            throw new IllegalStateException("AMapLocationClient is not initialized. Call init() first.");
+        }
+        if (PermissionUtil.hasPermission(context, LOCATION_PERMISSION)) {
+            LogUtil.d(TAG, "startLocation...");
             aMapLocationClient.startLocation();
             aMapLocationClient.enableBackgroundLocation(AMAP_NOTIFICATION_ID, createLocationNotification(context));
-        } else {
-            initLocation(context);
+        }else{
+            LogUtil.w(TAG, "startLocation: No location permission granted.");
+            throw new SecurityException("Location permissions are required to start location tracking.");
         }
     }
 

+ 2 - 2
pubspec.yaml

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 # In Windows, build-name is used as the major, minor, and patch parts
 # of the product and file versions while build-number is used as the build suffix.
-version: 1.1.2+112
+version: 1.1.5+115
 
 environment:
   sdk: ^3.5.0
@@ -196,7 +196,7 @@ dependencies:
   gravity_engine:
     git:
       url: http://git.atmob.com:28999/Atmob-Flutter/gravity_engine.git
-      ref: v0.0.2
+      ref: v5.0.3+0
 
   flutter_umeng:
     git: