tencent_location_flutter 0.1.0
tencent_location_flutter: ^0.1.0 copied to clipboard
Unofficial Flutter Tencent location plugin with federated Android and iOS implementations.
example/lib/main.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tencent_location_flutter/tencent_location_flutter.dart';
const String _defaultTencentLocationKey = 'VUXBZ-6IDKQ-G7D5L-4XDPR-6JFRQ-74BI3';
const MethodChannel _examplePermissionsChannel = MethodChannel(
'tencent_location_flutter_example/permissions',
);
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tencent Location Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF0D6EFD)),
useMaterial3: true,
),
home: const ExampleHomePage(),
);
}
}
class ExampleHomePage extends StatefulWidget {
const ExampleHomePage({super.key});
@override
State<ExampleHomePage> createState() => _ExampleHomePageState();
}
class _ExampleHomePageState extends State<ExampleHomePage> {
final TencentLocation _location = TencentLocation.instance;
final TextEditingController _keyController = TextEditingController(
text: _defaultTencentLocationKey,
);
final List<String> _logs = <String>[];
StreamSubscription<TencentLocationData>? _sessionSubscription;
StreamSubscription<TencentLocationError>? _sessionErrorSubscription;
LocationUpdateSession? _session;
TencentSdkInfo? _sdkInfo;
TencentLocationData? _latestLocation;
@override
void initState() {
super.initState();
_location.authorizationChanges.listen((LocationAuthorizationState state) {
_appendLog('authorization => ${state.toMap()}');
});
_location.locationErrors.listen((TencentLocationError error) {
_appendLog('error => ${error.toMap()}');
});
_location.headingUpdates.listen((HeadingData heading) {
_appendLog('heading => ${heading.toMap()}');
});
_location.geofenceEvents.listen((GeofenceEvent event) {
_appendLog('geofence => ${event.toMap()}');
});
_location.drUpdates.listen((DrPosition position) {
_appendLog('dr => ${position.toMap()}');
});
}
@override
void dispose() {
_sessionSubscription?.cancel();
_sessionErrorSubscription?.cancel();
_keyController.dispose();
super.dispose();
}
Future<void> _initialize() async {
await _location.setUserAgreePrivacy(true);
await _location.initialize(
InitializeOptions(
key: _keyController.text.trim(),
coordinateType: TencentLocationCoordinateType.gcj02,
requestLevel: TencentLocationRequestLevel.adminName,
mockEnable: false,
android: const AndroidInitOptions(
locationMode: TencentAndroidLocationMode.highAccuracy,
allowGps: true,
loadLibraryEnabled: true,
),
ios: const IosManagerOptions(
allowsBackgroundLocationUpdates: true,
pausesLocationUpdatesAutomatically: false,
),
),
);
final TencentSdkInfo sdkInfo = await _location.getSdkInfo();
setState(() => _sdkInfo = sdkInfo);
_appendLog('initialized => ${sdkInfo.toMap()}');
}
Future<void> _requestPermissions() async {
if (Platform.isAndroid || Platform.isIOS) {
final Object? result = await _examplePermissionsChannel.invokeMethod(
'requestLocationPermissions',
);
_appendLog('${Platform.operatingSystem} permission request => $result');
}
if (Platform.isIOS) {
await _location.ios.requestWhenInUseAuthorization();
}
final LocationAuthorizationState state = await _location
.authorizationStatus();
_appendLog('permission check => ${state.toMap()}');
}
Future<void> _getLocationOnce() async {
final TencentLocationData data = await _location.getLocationOnce(
options: const SingleLocationOptions(
requestLevel: TencentLocationRequestLevel.poi,
timeoutMillis: 10000,
),
);
setState(() => _latestLocation = data);
_appendLog('single => ${data.toMap()}');
}
Future<void> _startContinuous() async {
await _sessionSubscription?.cancel();
await _sessionErrorSubscription?.cancel();
final LocationUpdateSession session = await _location.startLocationUpdates(
LocationUpdateOptions(
intervalMillis: 15 * 1000,
requestLevel: TencentLocationRequestLevel.geo,
backgroundLocation: true,
androidRequest: const AndroidLocationRequestOptions(
intervalMillis: 15 * 1000,
requestLevel: TencentLocationRequestLevel.geo,
locationMode: TencentAndroidLocationMode.highAccuracy,
allowGps: true,
allowCache: true,
),
androidForegroundNotification:
const AndroidForegroundNotificationOptions(
id: 1001,
channelId: 'location_foreground',
channelName: 'Tencent Location',
title: 'Tencent Location',
text: 'Continuous location is running',
),
ios: const IosManagerOptions(
allowsBackgroundLocationUpdates: true,
pausesLocationUpdatesAutomatically: false,
),
),
);
_session = session;
_sessionSubscription = session.updates.listen((TencentLocationData data) {
setState(() => _latestLocation = data);
_appendLog('continuous(${session.id}) => ${data.toMap()}');
});
_sessionErrorSubscription = session.errors.listen((
TencentLocationError error,
) {
_appendLog('continuous error(${session.id}) => ${error.toMap()}');
});
_appendLog('continuous started => ${session.id}');
}
Future<void> _stopContinuous() async {
await _session?.stop();
await _sessionSubscription?.cancel();
await _sessionErrorSubscription?.cancel();
_appendLog('continuous stopped');
_session = null;
}
Future<void> _addGeofence() async {
await _location.addGeofence(
const GeofenceOptions(
tag: 'example-fence',
latitude: 22.543096,
longitude: 114.057865,
radiusMeters: 100,
),
);
_appendLog('${Platform.operatingSystem} geofence added');
}
Future<void> _startHeading() async {
await _location.startHeadingUpdates();
_appendLog('${Platform.operatingSystem} heading started');
}
Future<void> _stopHeading() async {
await _location.stopHeadingUpdates();
_appendLog('${Platform.operatingSystem} heading stopped');
}
Future<void> _requestIosTemporaryAccuracy() async {
final LocationAccuracyAuthorization auth = await _location.ios
.requestTemporaryFullAccuracyAuthorization(
const IosTemporaryAccuracyOptions(
purposeKey: 'TencentLocationAccuracy',
),
);
_appendLog('ios temporary accuracy => $auth');
}
Future<void> _startIosDr() async {
final TencentDrStartCode code = await _location.startDrEngine(
const TencentDrOptions(motionType: TencentDrMotionType.walk),
);
_appendLog('ios dr start => $code');
}
Future<void> _stopIosDr() async {
await _location.stopDrEngine();
_appendLog('ios dr stopped');
}
void _appendLog(String line) {
debugPrint(line);
setState(() {
_logs.insert(0, '${DateTime.now().toIso8601String()} $line');
if (_logs.length > 40) {
_logs.removeRange(40, _logs.length);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Tencent Location Example')),
body: SafeArea(
child: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
TextField(
controller: _keyController,
decoration: const InputDecoration(
labelText: 'Tencent LBS Key',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 12),
Wrap(
spacing: 12,
runSpacing: 12,
children: <Widget>[
FilledButton(
onPressed: _initialize,
child: const Text('Agree + Init'),
),
FilledButton(
onPressed: _requestPermissions,
child: const Text('Request Permissions'),
),
FilledButton(
onPressed: _getLocationOnce,
child: const Text('Single Location'),
),
FilledButton(
onPressed: _startContinuous,
child: const Text('Start Continuous'),
),
FilledButton(
onPressed: _stopContinuous,
child: const Text('Stop Continuous'),
),
if (Platform.isAndroid || Platform.isIOS)
FilledButton(
onPressed: _addGeofence,
child: const Text('Geofence'),
),
if (Platform.isAndroid || Platform.isIOS)
FilledButton(
onPressed: _startHeading,
child: const Text('Start Heading'),
),
if (Platform.isAndroid || Platform.isIOS)
FilledButton(
onPressed: _stopHeading,
child: const Text('Stop Heading'),
),
if (Platform.isIOS)
FilledButton(
onPressed: _requestIosTemporaryAccuracy,
child: const Text('Temp Accuracy'),
),
if (Platform.isIOS)
FilledButton(
onPressed: _startIosDr,
child: const Text('Start DR'),
),
if (Platform.isIOS)
FilledButton(
onPressed: _stopIosDr,
child: const Text('Stop DR'),
),
],
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('SDK Info: ${_sdkInfo?.toMap() ?? 'Not initialized'}'),
const SizedBox(height: 8),
Text(
'Latest Location: ${_latestLocation?.toMap() ?? 'N/A'}',
),
],
),
),
),
const SizedBox(height: 16),
const Text('Logs'),
const SizedBox(height: 8),
Container(
constraints: const BoxConstraints(minHeight: 240),
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.all(12),
child: SelectableText(
_logs.join('\n'),
style: const TextStyle(
color: Colors.white,
fontFamily: 'monospace',
),
),
),
],
),
),
);
}
}