Full Asset Tracking Example

This example shows:

  • Initialize Asset Tracking: Initialize asset tracking by calling the initialize() method of the AssetTracking class with the appropriate API key.
  • Check Permissions and Start Tracking: Before starting tracking, the application checks for location permissions, especially on Android devices. It ensures proper permission before initiating tracking.
  • Add Listener for Asset Tracking Callback: The application adds a listener to receive updates from the asset tracking service. This includes tracking status updates and location data.
  • Switch Asset Tracking Mode: Users can switch between different tracking modes, such as active, balanced, passive, or custom. The application updates the location configuration accordingly based on the selected mode.
  • Change Notification Configurations: Users can configure notification settings to track start and stop events. These configurations are platform-specific and handled appropriately for Android and iOS devices.
  • Start and Stop Tracking: The application provides buttons to start and stop tracking based on user input. It ensures that tracking is only started when all necessary configurations are set.
  • Display Tracking Status and Location Information: The application displays the current tracking status and location information in real-time. Users can monitor the tracking process and view location details as they are received.
  • Create a New Asset: Users can create a new asset profile within the application. This functionality allows for the management of multiple assets and tracking them separately.

home_screen.dart view source

1
import 'dart:io';
2
3
import 'package:flutter/material.dart';
4
import 'package:fluttertoast/fluttertoast.dart';
5
import 'package:nb_asset_tracking_flutter/nb_asset_tracking_flutter.dart';
6
import 'package:nb_asset_tracking_flutter_example/util/permiss_checker.dart';
7
import 'package:nb_asset_tracking_flutter_example/util/toast_mixin.dart';
8
import 'package:shared_preferences/shared_preferences.dart';
9
10
import '../util/consts.dart';
11
import 'create_asset.dart';
12
13
class HomeScreen extends StatefulWidget {
14
const HomeScreen({super.key});
15
16
@override
17
State<HomeScreen> createState() => _MyAppState();
18
}
19
20
class _MyAppState extends State<HomeScreen> with ToastMixin implements OnTrackingDataCallBack {
21
bool _isRunning = false;
22
bool isAllowMockLocation = false;
23
bool enableTrackingStartedNotification = true;
24
bool enableTrackingStopNotification = true;
25
final assetTracking = AssetTracking();
26
TrackingMode selectedOption = TrackingMode.active;
27
CustomIntervalMode selectedIntervalMode = CustomIntervalMode.distanceBased;
28
String trackingStatus = 'Tracking Status: ';
29
String locationInfo = '';
30
late SharedPreferences sharedPreferences;
31
final TextEditingController textEditingController = TextEditingController();
32
33
@override
34
void initState() {
35
super.initState();
36
assetTracking.initialize(apiKey: accessKey);
37
Stream<AssetResult> statusStream = assetTracking.isTracking().asStream();
38
statusStream.listen((value) {
39
_isRunning = value.data;
40
updateTrackingStatus(_isRunning);
41
});
42
43
assetTracking.addDataListener(this);
44
initSharedPreferences();
45
bindExistAssetId();
46
}
47
48
Future initSharedPreferences() async {
49
sharedPreferences = await SharedPreferences.getInstance();
50
51
AssetResult result = await assetTracking.getFakeGpsConfig();
52
53
bool allow = sharedPreferences.getBool(keyOfFakeGpsFlag) ?? result.data;
54
assetTracking.setFakeGpsConfig(allow: allow);
55
56
String trackingMode = sharedPreferences.getString(keyOfTrackingMode) ?? TrackingMode.active.name;
57
TrackingMode mode = TrackingMode.fromString(trackingMode);
58
assetTracking.setLocationConfig(config: LocationConfig.config(mode));
59
60
var envConfig = sharedPreferences.getString(keyOfEnvConfig);
61
if (envConfig?.isNotEmpty == true) {
62
assetTracking.setDataTrackingConfig(
63
config: DataTrackingConfig(baseUrl: EnvConfig.fromString(envConfig!) == EnvConfig.prod ? baseUrlProd : baseUrlStaging));
64
}
65
66
setState(() {
67
isAllowMockLocation = allow;
68
selectedOption = mode;
69
});
70
}
71
72
void bindExistAssetId() async {
73
SharedPreferences prefs = await SharedPreferences.getInstance();
74
String? boundId = prefs.getString(keyOfBoundId);
75
76
if (boundId == null) {
77
return;
78
}
79
80
AssetResult result = await assetTracking.bindAsset(customId: boundId);
81
if (!result.success) {
82
showToast("bind asset failed: ${result.msg}");
83
return;
84
} else {
85
showToast("Bind asset successfully with id: ${result.data}");
86
}
87
}
88
89
@override
90
void dispose() {
91
assetTracking.removeDataListener(this);
92
super.dispose();
93
}
94
95
void updateTrackingStatus(bool isRunning) {
96
setState(() {
97
_isRunning = isRunning;
98
final status = isRunning ? "ON" : "OFF";
99
trackingStatus = 'Tracking Status: $status';
100
if (!isRunning) {
101
locationInfo = "";
102
}
103
});
104
}
105
106
void startTracking() async {
107
if (Platform.isAndroid) {
108
var granted = await checkAndRequestLocationPermission();
109
if (!granted) {
110
showToast("Please granted location access for this app");
111
return;
112
}
113
}
114
SharedPreferences prefs = await SharedPreferences.getInstance();
115
String? boundId = prefs.getString(keyOfBoundId);
116
117
if (boundId == null) {
118
showToast("You mast bind a asset Id first");
119
return;
120
}
121
122
configNotificationConfig();
123
if (locationConfigAvailable()) {
124
assetTracking.startTracking();
125
}
126
127
}
128
129
void configNotificationConfig() {
130
if (Platform.isIOS) {
131
var iosNotificationConfig = IOSNotificationConfig();
132
iosNotificationConfig.showAssetEnableNotification = enableTrackingStartedNotification;
133
iosNotificationConfig.showAssetDisableNotification = enableTrackingStopNotification;
134
assetTracking.setIOSNotificationConfig(config: iosNotificationConfig);
135
}
136
}
137
138
bool locationConfigAvailable() {
139
if (selectedOption == TrackingMode.custom) {
140
num? customValue = num.tryParse(textEditingController.text);
141
if (customValue == null) {
142
Fluttertoast.showToast(
143
msg:
144
"Please enter ${selectedIntervalMode == CustomIntervalMode.distanceBased ? "distance interval" : "time interval"}",
145
gravity: ToastGravity.CENTER);
146
return false;
147
}
148
var locationConfig = LocationConfig();
149
switch (selectedIntervalMode) {
150
case CustomIntervalMode.distanceBased:
151
locationConfig = LocationConfig(smallestDisplacement: customValue.toDouble());
152
break;
153
case CustomIntervalMode.timeBased:
154
locationConfig = LocationConfig(intervalForAndroid: customValue.toInt() * 1000);
155
break;
156
}
157
assetTracking.setLocationConfig(config: locationConfig);
158
}
159
return true;
160
}
161
162
void stopTracking() {
163
configNotificationConfig();
164
assetTracking.stopTracking();
165
}
166
167
@override
168
Widget build(BuildContext context) {
169
return Scaffold(
170
appBar: AppBar(
171
title: const Text('Asset Tracking Flutter'),
172
),
173
body: SingleChildScrollView(
174
child: Padding(
175
padding: const EdgeInsets.symmetric(horizontal: 16.0),
176
child: Column(
177
crossAxisAlignment: CrossAxisAlignment.start,
178
children: [
179
_notificationConfig(),
180
Row(
181
children: [
182
const Text(
183
'Allow mock location',
184
style: TextStyle(fontSize: 16),
185
),
186
Transform.scale(
187
scale: 0.7,
188
child: Switch(
189
value: isAllowMockLocation,
190
onChanged: (value) {
191
setState(() {
192
isAllowMockLocation = value;
193
});
194
assetTracking.setFakeGpsConfig(allow: value);
195
sharedPreferences.setBool(keyOfFakeGpsFlag, value);
196
},
197
activeTrackColor: Colors.lightGreenAccent,
198
activeColor: Colors.green,
199
),
200
),
201
],
202
),
203
SizedBox(
204
height: 40,
205
child: RadioListTile<TrackingMode>(
206
title: const Text(
207
'TRACKING_MODE_ACTIVE',
208
style: TextStyle(fontSize: 15),
209
),
210
value: TrackingMode.active,
211
groupValue: selectedOption,
212
onChanged: _isRunning
213
? null
214
: (value) {
215
assetTracking.updateLocationConfig(config: LocationConfig.activeConfig());
216
setState(() {
217
selectedOption = value!;
218
});
219
sharedPreferences.setString(keyOfTrackingMode, selectedOption.name);
220
},
221
contentPadding: EdgeInsets.zero,
222
),
223
),
224
SizedBox(
225
height: 40,
226
child: RadioListTile<TrackingMode>(
227
title: const Text(
228
'TRACKING_MODE_BALANCED',
229
style: TextStyle(fontSize: 15),
230
),
231
value: TrackingMode.balanced,
232
groupValue: selectedOption,
233
onChanged: _isRunning
234
? null
235
: (value) {
236
assetTracking.updateLocationConfig(config: LocationConfig.balancedConfig());
237
setState(() {
238
selectedOption = value!;
239
});
240
sharedPreferences.setString(keyOfTrackingMode, selectedOption.name);
241
},
242
contentPadding: EdgeInsets.zero,
243
),
244
),
245
SizedBox(
246
height: 40,
247
child: RadioListTile<TrackingMode>(
248
title: const Text(
249
'TRACKING_MODE_PASSIVE',
250
style: TextStyle(fontSize: 15),
251
),
252
value: TrackingMode.passive,
253
groupValue: selectedOption,
254
onChanged: _isRunning
255
? null
256
: (value) {
257
assetTracking.updateLocationConfig(config: LocationConfig.passiveConfig());
258
setState(() {
259
selectedOption = value!;
260
});
261
sharedPreferences.setString(keyOfTrackingMode, selectedOption.name);
262
},
263
contentPadding: EdgeInsets.zero,
264
),
265
),
266
SizedBox(
267
height: 40,
268
child: RadioListTile<TrackingMode>(
269
title: const Text(
270
'TRACKING_MODE_CUSTOM',
271
style: TextStyle(fontSize: 15),
272
),
273
value: TrackingMode.custom,
274
groupValue: selectedOption,
275
onChanged: _isRunning
276
? null
277
: (value) {
278
assetTracking.updateLocationConfig(config: LocationConfig());
279
setState(() {
280
selectedOption = value!;
281
});
282
sharedPreferences.setString(keyOfTrackingMode, selectedOption.name);
283
},
284
contentPadding: EdgeInsets.zero,
285
),
286
),
287
Padding(
288
padding: const EdgeInsets.only(left: 48.0, top: 15),
289
child: Row(
290
children: [
291
Platform.isAndroid
292
? DropdownButton<CustomIntervalMode>(
293
value: selectedIntervalMode,
294
underline: Container(
295
height: 1,
296
color: Colors.grey,
297
),
298
items: const [
299
DropdownMenuItem(
300
value: CustomIntervalMode.distanceBased,
301
child: Text(
302
'Distance based',
303
style: TextStyle(fontSize: 15),
304
),
305
),
306
DropdownMenuItem(
307
value: CustomIntervalMode.timeBased,
308
child: Text(
309
'Time based',
310
style: TextStyle(fontSize: 15),
311
),
312
),
313
],
314
alignment: AlignmentDirectional.topCenter,
315
onChanged: customOptionAvailable()
316
? (value) {
317
setState(() {
318
selectedIntervalMode = value!;
319
});
320
}
321
: null,
322
)
323
: Container(),
324
Expanded(
325
child: Container(
326
margin: EdgeInsets.only(left: 8, right: 8),
327
height: 38,
328
child: TextField(
329
enabled: customOptionAvailable(),
330
controller: textEditingController,
331
maxLines: 1,
332
keyboardType: TextInputType.number,
333
style: TextStyle(
334
color: customOptionAvailable() ? Colors.black : Colors.grey.shade400, fontSize: 16.0),
335
decoration: InputDecoration(
336
contentPadding: const EdgeInsets.only(left: 6, right: 6, top: 0, bottom: 0),
337
border: const OutlineInputBorder(),
338
hintText: selectedIntervalMode == CustomIntervalMode.distanceBased
339
? "Dist. in meters"
340
: "Time in seconds",
341
hintStyle: const TextStyle(color: Colors.grey, fontSize: 15.0))),
342
),
343
),
344
],
345
),
346
),
347
348
Padding(
349
padding: const EdgeInsets.only(top: 20),
350
child: Row(
351
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
352
children: [
353
Expanded(
354
child: Padding(
355
padding: const EdgeInsets.symmetric(horizontal: 2.0),
356
child: ElevatedButton(
357
onPressed: _isRunning
358
? null
359
: () {
360
startTracking();
361
},
362
child: const Text('START TRACKING', style: TextStyle(fontSize: 13)),
363
),
364
),
365
),
366
Expanded(
367
child: Padding(
368
padding: const EdgeInsets.symmetric(horizontal: 2.0),
369
child: ElevatedButton(
370
onPressed: _isRunning
371
? () {
372
stopTracking();
373
}
374
: null,
375
child: const Text('STOP TRACKING', style: TextStyle(fontSize: 13)),
376
),
377
),
378
),
379
],
380
),
381
),
382
Padding(
383
padding: const EdgeInsets.only(top: 18.0),
384
child: Text(trackingStatus),
385
),
386
const SizedBox(
387
height: 16,
388
),
389
Text(locationInfo),
390
const SizedBox(
391
height: 16,
392
),
393
SizedBox(
394
width: double.infinity,
395
child: Padding(
396
padding: const EdgeInsets.symmetric(horizontal: 5.0),
397
child: ElevatedButton(
398
onPressed: () async {
399
AssetResult assetResult = await assetTracking.isTracking();
400
if(assetResult.data) {
401
Fluttertoast.showToast(msg: "please stop tracking before editing asset profile");
402
return;
403
}
404
pushToCreateAsset();
405
},
406
child: const Text('Create new Asset'),
407
),
408
),
409
),
410
const SizedBox(
411
height: 16,
412
),
413
// SizedBox(
414
// width: double.infinity,
415
// child: ElevatedButton(
416
// onPressed: () {
417
// // Do something
418
// },
419
// child: const Text('View data uploaded logs'),
420
// ),
421
// )
422
],
423
),
424
),
425
),
426
);
427
}
428
429
bool customOptionAvailable() {
430
return !_isRunning && selectedOption == TrackingMode.custom;
431
}
432
433
void pushToCreateAsset() {
434
Navigator.push(
435
context,
436
MaterialPageRoute(builder: (context) => const CreateAssteScreen()),
437
);
438
}
439
440
@override
441
void onLocationFailure(String message) {
442
setState(() {
443
locationInfo = "------- Location Info ------- \n"
444
"$message";
445
});
446
}
447
448
@override
449
void onLocationSuccess(NBLocation location) {
450
setState(() {
451
if (_isRunning) {
452
locationInfo = "------- Location Info ------- \n"
453
"Provider: ${location.provider} \n"
454
"Latitude: ${location.latitude}\n"
455
"Longitude: ${location.longitude}\n"
456
"Altitude: ${location.altitude}\n"
457
"Accuracy: ${location.accuracy}\n"
458
"Speed: ${location.speed}\n"
459
"Bearing: ${location.heading}\n"
460
"Time: ${location.timestamp}\n";
461
}
462
});
463
}
464
465
@override
466
void onTrackingStart(String message) {
467
updateTrackingStatus(true);
468
}
469
470
@override
471
void onTrackingStop(String message) {
472
updateTrackingStatus(false);
473
}
474
475
Widget _notificationConfig() {
476
if (Platform.isAndroid) {
477
return Container();
478
}
479
return Column(
480
children: [
481
Row(
482
children: [
483
const Text(
484
'Enable Tracking Started Notification',
485
style: TextStyle(fontSize: 16),
486
),
487
Transform.scale(
488
scale: 0.7,
489
child: Switch(
490
value: enableTrackingStartedNotification,
491
onChanged: (value) {
492
setState(() {
493
enableTrackingStartedNotification = value;
494
});
495
sharedPreferences.setBool(keyOfEnableTrackingStartedNotification, value);
496
},
497
activeTrackColor: Colors.lightGreenAccent,
498
activeColor: Colors.green,
499
),
500
),
501
],
502
),
503
Row(
504
children: [
505
const Text(
506
'Enable Tracking Stopped Notification',
507
style: TextStyle(fontSize: 16),
508
),
509
Transform.scale(
510
scale: 0.7,
511
child: Switch(
512
value: enableTrackingStopNotification,
513
onChanged: (value) {
514
setState(() {
515
enableTrackingStopNotification = value;
516
});
517
sharedPreferences.setBool(keyOfEnableTrackingStopNotification, value);
518
},
519
activeTrackColor: Colors.lightGreenAccent,
520
activeColor: Colors.green,
521
),
522
),
523
],
524
),
525
],
526
);
527
}
528
}

These functionalities collectively enable users to manage asset tracking within the application, including configuring settings, initiating tracking, receiving notifications, and viewing relevant information.

  1. Initialize Asset Tracking:

    1. The code initializes the asset tracking module using a specific API key. This likely involves connecting to an external service or setting up internal tracking mechanisms.
  2. Check Permissions and Start Tracking:

    1. It checks if the necessary permissions to access the device's location are granted. If not, it may prompt the user to grant these permissions.
    2. Once permissions are granted, the code initiates the asset-tracking process, which may involve starting a service or initiating location tracking.
  3. Add Listener for Asset Tracking Callback:

    1. A listener is set up to receive updates from the asset tracking module. This listener likely handles events such as tracking start, stop, location updates, or errors.
  4. Switch Asset Tracking Mode:

    1. Users can switch between different tracking modes, such as active, balanced, passive, or custom. Each mode likely adjusts how frequently location data is collected or the level of accuracy required.
  5. Change Notification Configurations:

    1. Users can configure whether to receive notifications for tracking start and stop events. This allows for customization of the user experience based on preferences.
  6. Start and Stop Tracking:

    1. Users can initiate or terminate the tracking process through the application's interface. This functionality likely interacts with the underlying tracking service or module to control its behavior.
  7. Display Tracking Status and Location Information:

    1. The application provides visual feedback to users regarding the current tracking status (e.g., whether tracking is active or inactive)。
    2. Location information may be displayed to users in real-time, including latitude, longitude, speed, and accuracy.
  • Initialize Asset Tracking

    • assetTracking.initialize(apiKey: accessKey);
    • Add Listener for Asset Tracking Callback
    • assetTracking.addDataListener(this);
  • Check Permissions and Start Tracking (Called from startTracking method)

    • var granted = await checkAndRequestLocationPermission();
    • assetTracking.startTracking();
    • Switch Asset Tracking Mode (Called from onChanged callbacks of RadioListTile widgets)
    • assetTracking.updateLocationConfig(config: LocationConfig.activeConfig());
    • assetTracking.updateLocationConfig(config: LocationConfig.balancedConfig());
    • assetTracking.updateLocationConfig(config: LocationConfig.passiveConfig());
    • assetTracking.updateLocationConfig(config: LocationConfig());
  • Change Notification Configurations (Called from configNotificationConfig method)

    • assetTracking.setIOSNotificationConfig(config: iosNotificationConfig);
  • Start and Stop Tracking (Called from startTracking and stopTracking methods)

    • assetTracking.startTracking();
    • assetTracking.stopTracking();

© 2024 NextBillion.ai all rights reserved.