乐趣区

关于android:停车场找不到自己的车停在哪儿教你开发一款Find-My-CarApp

您会遗记您的车停在哪了吗?如果会,这款利用是您不错的一个抉择!

在本指南中,将实现如下性能:

l 应用华为地图服务来标记车辆的地位,并在华为地图上展现返回车辆所在位置的门路。

l 应用华为定位服务来获取用户的以后地位。

l 应用 Shared Preferences 来存储车辆停放地位数据。

l 应用 Directions API 来布局返回车辆所在位置的门路。

首先,您须要注册一个华为开发者账户,并在 AppGallery Connect 中增加一个利用我的项目。开启“地图服务”和“定位服务”开关,以便在您的利用中应用服务。如果您没有华为开发者账户,不分明具体步骤,请参考如下链接:

l 注册华为开发者账户

l 配置 AGC 信息

l 集成地图服务 Flutter 插件

l 集成定位服务 Flutter 插件

重要:增加利用时,输出的利用包名该当与您的 Flutter 我的项目包名统一。

留神:下载 agconnect-services.json 文件前,请确保已开明所需的 HMS 服务。

权限

为失常应用 HMS 服务,您须要在 AndroidManifest.xml 文件中增加如下权限:

<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>  
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

增加依赖

实现上述步骤后,需在 pubspec.yaml 文件中增加对所需 HMS 服务对应的 Flutter 插件的依赖。您能够在 pub.dev 中找到最新版本的插件。

dependencies:  
 flutter:  
   sdk: flutter  
 huawei_map: ^5.0.3+302  
 huawei_location: ^5.0.0+301  
 shared_preferences: ^0.5.12+4  
 http: ^0.12.2

增加插件依赖后,运行 flutter pub get 命令。

至此,所有增加的插件均已准备就绪。

申请定位权限并获取地位

PermissionHandler _permissionHandler = PermissionHandler();
 FusedLocationProviderClient _locationService = FusedLocationProviderClient();
 Location _myLocation;
 LatLng _center;
 
 @override
 void initState() {requestPermission();
   super.initState();}
 
 requestPermission() async {bool hasPermission = await _permissionHandler.hasLocationPermission();
   if (!hasPermission)
     hasPermission = await _permissionHandler.requestLocationPermission();
   if (hasPermission) getLastLocation();}
 
 getLastLocation() async {_myLocation = await _locationService.getLastLocation();
   setState(() {_center = LocationUtils.locationToLatLng(_myLocation);
   });
 }

Location 数据类型来自华为定位服务。LatLng 数据类型来自华为地图服务。调用 getLastLocation 办法时会获取到一个 Location 取值,您须要将其转换为 LatLng 取值,以便在 HuaweiMap 控件中应用。

class LocationUtils {static LatLng locationToLatLng(Location location) =>
      LatLng(location.latitude, location.longitude);
}

增加 HuaweiMap 控件和按钮

如果_myLocation 变量取值不是 null,示意已获取到用户地位,且利用能够启动并将该地位赋值给 HuaweiMap 控件中的指标属性。

Stack(
  children: [
    HuaweiMap(
      initialCameraPosition: CameraPosition(
         target: _center,
         zoom: _zoom,
      ),
      markers: _markers,
      polylines: _polylines,
      mapType: MapType.normal,
      tiltGesturesEnabled: true,
      buildingsEnabled: true,
      compassEnabled: true,
      zoomControlsEnabled: true,
      rotateGesturesEnabled: true,
      myLocationButtonEnabled: true,
      myLocationEnabled: true,
      trafficEnabled: false,
    ),
    Positioned(
      left: 20,
      top: 20,
      child: _isCarParked
        ? CustomButton(
            text: "Go to My Car",
            onPressed: goToMyCar,
          )
        : CustomButton(
            text: "Set Location",
            onPressed: parkMyCar,
          ),
    ),           
  ],
),

应用 Stack 封装 HuaweiMap 控件,并增加按钮。按钮名称和性能会随车辆状态的变动而扭转。

停车并设置地位

void parkMyCar() {getLastLocation();
    Prefs.setCarLocation(_myLocation);
    Prefs.setIsCarParked(true);
    getCarStatus();}
 
  getLastLocation() async {_myLocation = await _locationService.getLastLocation();
    setState(() {_center = LocationUtils.locationToLatLng(_myLocation);
    });
  }
 
  getCarStatus() async {_isCarParked = await Prefs.getIsCarParked();
    setState(() {});
    addMarker();}
 
  addMarker() async {if (_isCarParked && _markers.isEmpty) {LatLng carLocation = await Prefs.getCarLocation();
      setState(() {
        _markers.add(Marker(markerId: MarkerId("myCar"),
          position: carLocation,
        ));
      });
    }
  }

增加地位时,获取用户的最初地位,更新_myLocation 和_center,在应用 SharedPreferences 存储数据的 Prefs 类中设置地位,而后增加一个标记来展现车辆的地位。

如下示例代码中,创立了一个名为 Prefs 的 helper 类,并应用 SharedPreferences 将办法离开。

class Prefs {
  static const String _latitude = "car_location_latitude";
  static const String _longitude = "car_location_longitude";
  static const String _isLocationSet = "is_location_set";
 
  static void setCarLocation(Location location) async {SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setDouble(_latitude, location.latitude);
    prefs.setDouble(_longitude, location.longitude);
    print("Car's location has been set to (${location.latitude}, ${location.longitude})");
  }
 
  static Future<LatLng> getCarLocation() async {SharedPreferences prefs = await SharedPreferences.getInstance();
    double lat = prefs.getDouble(_latitude);
    double lng = prefs.getDouble(_longitude);
    return LatLng(lat, lng);
  }
 
  static void setIsCarParked(bool value) async {SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setBool(_isLocationSet, value);
  }
 
  static Future<bool> getIsCarParked() async {SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getBool(_isLocationSet)?? false;
  }
}

点击 Set Location 按钮后,将设置以后地位并在利用内存中应用 SharedPreferences 存储地位。此外,该按钮的名称和性能也将扭转,以便通过扭转后的按钮返回到停车地位。

查找车辆

在返回时,点击 Go to My Car 按钮。Directions API 会查找一条从以后地位到停车地位的路线,而后利用会在华为地图上通过折线来展现该路线。

void goToMyCar() async {getLastLocation();
   addMarker();
   LatLng carLocation = await Prefs.getCarLocation();
   DirectionRequest request = DirectionRequest(
       origin: Destination(
         lat: _myLocation.latitude,
         lng: _myLocation.longitude,
       ),
       destination: Destination(
         lat: carLocation.lat,
         lng: carLocation.lng,
       ),
   );
   DirectionResponse response = await DirectionUtils.getDirections(request);
   drawRoute(response);
 }
 
 drawRoute(DirectionResponse response) {if (_polylines.isNotEmpty) _polylines.clear();
   var steps = response.routes[0].paths[0].steps;
   for (int i = 0; i < steps.length; i++) {for (int j = 0; j < steps[i].polyline.length; j++) {_points.add(steps[i].polyline[j].toLatLng());
     }
   }
   setState(() {
     _polylines.add(
       Polyline(polylineId: PolylineId("route"),
           points: _points,
           color: Colors.redAccent),
     );
   });
 }

应用 Directions API 时需特地留神,您须要在 HTTP posting 前将您编码后的 API key 增加到 URL 地址开端。能够通过 encodeComponent 办法来实现,如下代码所示。

class ApplicationUtils {static String encodeComponent(String component) => Uri.encodeComponent(component);
 
  static const String API_KEY = "YOUR_API_KEY";
 
  // HTTPS POST
  static String url =
      "https://mapapi.cloud.huawei.com/mapApi/v1/routeService/walking?key=" +
          encodeComponent(API_KEY);
}
 
class DirectionUtils {static Future<DirectionResponse> getDirections(DirectionRequest request) async {
    var headers = <String, String>{"Content-type": "application/json",};
    var response = await http.post(ApplicationUtils.url,
        headers: headers, body: jsonEncode(request.toJson()));
 
    if (response.statusCode == 200) {
      DirectionResponse directionResponse =
          DirectionResponse.fromJson(jsonDecode(response.body));
      return directionResponse;
    } else
      throw Exception('Failed to load direction response');
  }
}

例如,如果原始 API key 是 ABC/DFG+,则转换后果为 ABC%2FDFG%2B.

至此,咱们实现了 2 大性能:地位存储以及回到存储数据所代表的地位。此外,还增加了一个 floatingActionButton(浮动按钮),用来重置地位数据和清屏。

clearScreen() {Prefs.setIsCarParked(false);  
   Prefs.setCarLocation(null);  
   _markers.clear();  
   _polylines.clear();  
   getCarStatus();}  
Stack(  
 children: [  
  /*  
    * Other widgets  
    */  
   Positioned(  
     left: 20,  
     bottom: 20,  
     child: FloatingActionButton(  
       backgroundColor: Colors.blueGrey,  
       child: Icon(Icons.clear),  
       onPressed: clearScreen,  
    ),  
   ),  
 ],  
),

您能够在 GitHub 页面查看残缺的代码。页面链接:GitHub

舒适提醒

l Directions API 反对三种门路布局:步行、骑行以及驾车。每种门路布局对应的 URL 都不同。

l 增加 API key 到 URL 开端前,请先对进行编码。否则,您将无奈获取响应。

l 您能够在 agconnect-services.json 文件中查看您的 API key。

更多详情请点击:

l 地图服务文档

l 定位服务文档

l Directions API 文档

l 地图服务 Demo 我的项目

l 定位服务 Demo 我的项目

原文链接:https://developer.huawei.com/…
原作者:胡椒

退出移动版