In this page

Asset profile Operations

This detailed example walks you through the following steps:

  1. Creating a New Asset Based on User Input: Learn how to generate a new asset within your application, leveraging user input to create assets dynamically.

  2. Binding User-Created Asset IDs to the Current Device: Discover the process of associating user-generated asset IDs with the device you're currently using, facilitating tracking and management of these assets.

  3. Starting and Stopping Tracking Based on User Operations: Gain insights into how to initiate and halt tracking operations, giving users control over the tracking process.

  4. Switching Between Tracking Modes Based on User Operations: Learn how to transition between different tracking modes, providing flexibility and adaptability to user preferences.

  5. Receiving AssetTrackingCallbacks and Displaying Results in the User Interface: Explore how to handle AssetTrackingCallbacks and effectively communicate tracking results to the user interface, ensuring a seamless and informative user experience.

For all code examples, refer to iOS Tracking Android Code Examples

SetProfileViewController view source

1
2class SetProfileViewController: UIViewController, UIGestureRecognizerDelegate {
3    @IBOutlet weak var editCustomId: UITextField!
4    @IBOutlet weak var editAssetName: UITextField!
5    @IBOutlet weak var editAssetDescription: UITextField!
6    @IBOutlet weak var editAssetAttributes: UITextField!
7    @IBOutlet weak var lastAssetId: UITextField!
8    @IBOutlet weak var createAsset: UIButton!
9    
10    @IBOutlet weak var editAssetId: UITextField!
11    @IBOutlet weak var bindAsset: UIButton!
12    
13    var customId: String = ""
14    var assetName: String = ""
15    var assetDescription: String = ""
16    var assetAttributes: String = ""
17    var assetId: String = ""
18    
19    let userDefaults: UserDefaults = UserDefaults.standard
20    
21    override func viewDidLoad() {
22        super.viewDidLoad()
23        self.navigationController?.interactivePopGestureRecognizer?.delegate = self
24        self.hideKeyboardWhenTappedAround()
25        initData()
26        setUpInitialView()
27        addGestureEvents()
28    }
29    
30    override func viewWillAppear(_ animated: Bool) {
31        self.navigationController?.setNavigationBarHidden(true, animated: true)
32    }
33    
34    private func initData() {
35        customId = userDefaults.string(forKey: Constants.CUSTOM_ID_KEY) ?? UUID().uuidString.lowercased()
36        assetName = userDefaults.string(forKey: Constants.ASSET_NAME_KEY) ?? "my car"
37        assetDescription = userDefaults.string(forKey: Constants.ASSET_DESCRIPTION_KEY) ?? "a luxury BMW"
38        assetAttributes = userDefaults.string(forKey: Constants.ASSET_ATTRIBUTES_KEY) ?? "a test attribute"
39        
40        assetId = userDefaults.string(forKey: Constants.ASSET_ID_KEY) ?? ""
41    }
42    
43    private func setUpInitialView(){
44        editCustomId.delegate = self
45        editAssetName.delegate = self
46        editAssetDescription.delegate = self
47        editAssetAttributes.delegate = self
48        editAssetId.delegate = self
49        
50        editCustomId.text = customId
51        editAssetName.text = assetName
52        editAssetDescription.text = assetDescription
53        editAssetAttributes.text = assetAttributes
54        editAssetId.text = assetId
55        lastAssetId.text = userDefaults.string(forKey: Constants.LAST_BIND_ASSET_ID_KEY) ?? ""
56        
57        createAsset.setTitleColor(.white, for: .normal)
58        createAsset.layer.cornerRadius = 10
59        createAsset.layer.backgroundColor = UIColor.systemBlue.cgColor
60        
61        bindAsset.setTitleColor(.systemBlue, for: .normal)
62        bindAsset.layer.cornerRadius = 10
63        bindAsset.layer.borderWidth = 1.0
64        bindAsset.layer.borderColor = UIColor.systemBlue.cgColor
65    }
66    
67    private func addGestureEvents() {
68        createAsset.addTarget(self, action: #selector(onCreateAssetTapped), for: .touchUpInside)
69        bindAsset.addTarget(self, action: #selector(onBindAssetTapped), for: .touchUpInside)
70    }
71    
72    func isLauncherScreen() -> Bool {
73        return self.navigationController?.viewControllers.count == 1
74    }
75    
76    func lanchToHomeView() {
77        let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController")
78        self.view.window?.rootViewController = UINavigationController(rootViewController: viewController)
79    }
80    
81    private func saveAssetProfile(assetId: String){
82        userDefaults.set(customId, forKey: Constants.CUSTOM_ID_KEY)
83        userDefaults.set(assetName, forKey: Constants.ASSET_NAME_KEY)
84        userDefaults.set(assetDescription, forKey: Constants.ASSET_DESCRIPTION_KEY)
85        userDefaults.set(assetAttributes, forKey: Constants.ASSET_ATTRIBUTES_KEY)
86        userDefaults.set(assetId, forKey: Constants.ASSET_ID_KEY)
87    }
88    
89    @objc private func onCreateAssetTapped() {
90        if (assetName.isEmpty) {
91            let toastView = ToastView(message: "Please enter asset name")
92            toastView.show()
93            return
94        }
95        
96        if(AssetTracking.shared.isRunning()){
97            let toastView = ToastView(message: "Asset tracking is ON, please turn off tracking before creating new asset!")
98            toastView.show()
99            return
100        }
101        
102        let assetProfile: AssetProfile = AssetProfile.init(customId: customId, assetDescription: assetDescription, name: assetName, attributes: ["test": assetAttributes])
103        
104        AssetTracking.shared.createAsset(assetProfile: assetProfile) { assetCreationResponse in
105            let assetId = assetCreationResponse.data.id
106            self.editAssetId.text = assetId
107            self.saveAssetProfile(assetId: assetId)
108        } errorHandler: { error in
109            let errorMessage = error.localizedDescription
110            let toastView = ToastView(message: "Create asset failed: " + errorMessage)
111            toastView.show()
112        }
113    }
114    
115    private func showForceBindDialog(assetId: String, warningMessage: String) {
116        // Create an alert controller
117        let alertController = UIAlertController(title: "", message: warningMessage + ", do you want to clear local data and force bind to new asset id?", preferredStyle: .alert)
118        
119        let okAction = UIAlertAction(title: "Proceed", style: .default) { (_) in
120            self.dismiss(animated: true, completion: nil)
121            AssetTracking.shared.forceBindAsset(assetId: assetId) { responseCode in
122                let toastView = ToastView(message: "Force bind new asset successfully with assetId: " + assetId)
123                toastView.show()
124                
125                self.userDefaults.set(true, forKey: Constants.IS_NOT_FIRST_INSTALLATION_KEY)
126                self.userDefaults.set(assetId, forKey: Constants.LAST_BIND_ASSET_ID_KEY)
127                
128                if self.isLauncherScreen() {
129                    self.lanchToHomeView()
130                } else {
131                    self.navigationController?.popViewController(animated: true)
132                }
133            } errorHandler: { error in
134                let errorMessage = error.localizedDescription
135                let toastView = ToastView(message: "Bind asset failed: " + errorMessage)
136                toastView.show()
137            }
138        }
139        alertController.addAction(okAction)
140        
141        // Add "Cancel" button
142        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in
143            self.dismiss(animated: true, completion: nil)
144        }
145        alertController.addAction(cancelAction)
146        
147        // Show the alert
148        present(alertController, animated: true, completion: nil)
149    }
150    
151    @objc private func onBindAssetTapped() {
152        guard let assetId = editAssetId.text else {
153            let toastView = ToastView(message: "Please enter asset id")
154            toastView.show()
155            return
156        }
157        
158        AssetTracking.shared.bindAsset(assetId: assetId) { responseCode in
159            let toastView = ToastView(message: "Bind asset successfully with id: " + assetId)
160            toastView.show()
161            
162            self.userDefaults.set(true, forKey: Constants.IS_NOT_FIRST_INSTALLATION_KEY)
163            self.userDefaults.set(assetId, forKey: Constants.LAST_BIND_ASSET_ID_KEY)
164            
165            if self.isLauncherScreen() {
166                self.lanchToHomeView()
167            } else {
168                self.navigationController?.popViewController(animated: true)
169            }
170        } errorHandler: { error in
171            let errorMessage = error.localizedDescription
172            
173            if (errorMessage.contains(AssetTrackingApiExceptionType.UN_UPLOADED_LOCATION_DATA.rawValue)) {
174                self.showForceBindDialog(assetId: assetId, warningMessage: errorMessage)
175            } else {
176                let toastView = ToastView(message: "Bind asset failed: " + errorMessage)
177                toastView.show()
178            }
179        }
180        
181    }
182    
183}
184extension SetProfileViewController{
185    func hideKeyboardWhenTappedAround() {
186        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
187        tap.cancelsTouchesInView = false
188        view.addGestureRecognizer(tap)
189    }
190    
191    @objc private func dismissKeyboard() {
192        view.endEditing(true)
193    }
194    
195}
196extension SetProfileViewController: UITextFieldDelegate {
197    public func textFieldDidChangeSelection(_ textField: UITextField) {
198        let text = textField.text?.trimmingCharacters(in: CharacterSet.whitespaces) ?? ""
199        if textField == self.editCustomId {
200            customId = text
201        } else if textField == self.editAssetName {
202            assetName = text
203        } else if textField == self.editAssetDescription {
204            assetDescription = text
205        } else if textField == self.editAssetAttributes {
206            assetAttributes = text
207        } else if textField == self.editAssetId {
208            assetId = text
209        }
210    }
211    
212    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
213        textField.resignFirstResponder()
214        return true
215    }
216}

ExtendedTrackingViewController view source

1class ExtendedTrackingViewController: UIViewController, AssetTrackingCallback {
2    @IBOutlet weak var locationInfo: UILabel!
3    @IBOutlet weak var trackingStatus: UILabel!
4    @IBOutlet weak var trackingModeSelector: UISegmentedControl!
5    @IBOutlet weak var startTracking: UIButton!
6    @IBOutlet weak var stopTracking: UIButton!
7    @IBOutlet weak var createAsset: UIButton!
8    @IBOutlet weak var viewDataLogs: UIButton!
9    var assetTracking: AssetTracking = AssetTracking.shared
10    
11    override func viewDidLoad() {
12        super.viewDidLoad()
13        assetTracking.initialize(apiKey: "YOUR_API_KEY")
14        
15        assetTracking.delegate = self
16
17        startTracking.setTitle("Start Tracking", for: .normal)
18        startTracking.setTitleColor(.white, for: .normal)
19        startTracking.layer.cornerRadius = 10
20        startTracking.layer.backgroundColor = UIColor.systemBlue.cgColor
21        
22        stopTracking.setTitle("Stop Tracking", for: .normal)
23        stopTracking.setTitleColor(.white, for: .normal)
24        stopTracking.layer.cornerRadius = 10
25        stopTracking.layer.backgroundColor = UIColor.systemBlue.cgColor
26        
27        bindExistingAssetId()
28        setUpButtons()
29        updateTrackingStatus()
30    }
31    
32    override func viewWillAppear(_ animated: Bool) {
33        self.navigationController?.setNavigationBarHidden(true, animated: true)
34    }
35    
36    private func bindExistingAssetId(){
37        let assetId = UserDefaults.standard.string(forKey: Constants.LAST_BIND_ASSET_ID_KEY) ?? ""
38        
39        if(!assetId.isEmpty) {
40            AssetTracking.shared.bindAsset(assetId: assetId) { responseCode in
41                let toastView = ToastView(message: "Bind asset successfully with id: " + assetId)
42                toastView.show()
43            } errorHandler: { error in
44                let errorMessage = error.localizedDescription
45                let toastView = ToastView(message: "Bind asset failed: " + errorMessage)
46                toastView.show()
47            }
48        }
49    }
50    
51    private func setUpButtons(){
52        createAsset.setTitleColor(.white, for: .normal)
53        createAsset.layer.cornerRadius = 10
54        createAsset.layer.backgroundColor = UIColor.systemBlue.cgColor
55        
56        viewDataLogs.setTitleColor(.systemBlue, for: .normal)
57        viewDataLogs.layer.cornerRadius = 10
58        viewDataLogs.layer.borderWidth = 1.0
59        viewDataLogs.layer.borderColor = UIColor.systemBlue.cgColor
60        
61        createAsset.addTarget(self, action: #selector(onCreateAssetTapped), for: .touchUpInside)
62        
63        viewDataLogs.addTarget(self, action: #selector(onViewDataLogsTapped), for: .touchUpInside)
64    }
65    
66    @objc private func onCreateAssetTapped() {
67        if assetTracking.isRunning() {
68            let toastView = ToastView(message: "please stop tracking before editing asset profile")
69            toastView.show()
70            return
71        }
72
73        let setProfileViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SetProfileViewController") as! SetProfileViewController
74        self.navigationController?.pushViewController(setProfileViewController, animated: true)
75    }
76    
77    @objc private func onViewDataLogsTapped() {
78        let dataUploadLogVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DataUploadLogViewController") as! DataUploadLogViewController
79        self.navigationController?.pushViewController(dataUploadLogVC, animated: true)
80    }
81    
82    
83    @IBAction func startTracking(_ sender: Any) {
84        let assetId = assetTracking.getAssetId()
85        
86        if (assetId.isEmpty){
87            let toastView = ToastView(message: "Please bind asset first before start tracking!")
88            toastView.show()
89            return
90        }
91        
92        assetTracking.startTracking()
93    }
94    
95    @IBAction func stopTracking(_ sender: Any) {
96        locationInfo.text = ""
97        assetTracking.stopTracking()
98    }
99    
100    
101    @IBAction func onTrackingModeChanged(_ sender: Any) {
102        var trackingMode: TrackingMode = TrackingMode.ACTIVE
103        switch trackingModeSelector.selectedSegmentIndex {
104        case 0:
105            trackingMode = .ACTIVE
106        case 1:
107            trackingMode = .BALANCED
108        case 2:
109            trackingMode = .PASSIVE
110        default:
111            break
112        }
113        
114        let locationConfig = LocationConfig(trackingMode: trackingMode)
115        assetTracking.updateLocationConfig(config: locationConfig)
116    }
117    
118    func onTrackingStart(assetId: String) {
119        updateTrackingStatus()
120    }
121    
122    func onTrackingStop(assetId: String, trackingDisableType: TrackingDisableType) {
123        updateTrackingStatus()
124    }
125    
126    func onLocationSuccess(location: CLLocation) {
127        locationInfo.text = """
128                        --------- Location Info ---------
129            Latitude: \(location.coordinate.latitude)
130            Longitude: \(location.coordinate.longitude)
131            Altitude: \(location.altitude)
132            Accuracy: \(location.horizontalAccuracy)
133            Speed: \(location.speed)
134            Bearing: \(location.course)
135            Time: \(location.timestamp)
136            """
137    }
138    
139    func showLocationAlert() {
140        let alert = UIAlertController(title: "Location Services Disabled", message: "To enable location services, please go to Settings > Privacy > Location Services.", preferredStyle: .alert)
141        alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
142        
143        present(alert, animated: true, completion: nil)
144    }
145    
146    func onLocationFailure(error: Error) {
147    }
148    
149    func onLocationServiceOff() {
150        showLocationAlert()
151    }
152    
153    
154    func updateTrackingStatus() {
155        trackingStatus.text = "Tracking Status: \(assetTracking.isRunning() ? "ON" : "OFF")"
156        if !assetTracking.isRunning() {
157            locationInfo.text = ""
158        }
159    }
160    
161}

Upon executing the code example provided above, your app's appearance will resemble the following snippet:

Asset Profile Page Asset Tracking Page

Code Highlights

The SetProfileViewController class inherits from the UIViewController class, which is the base class for all view controllers in iOS.

  1. The class has several outlet properties: editCustomId, editAssetName, editAssetDescription, editAssetAttributes, lastAssetId, createAsset, and bindAsset. These properties are linked to the corresponding UI elements in the view controller's storyboard.

  2. createAsset(): This method creates a new asset with the specified custom ID, asset name, description, and attributes. The method calls the AssetTracking.shared.createAsset() method to make the API request.

  3. bindAsset(): This method binds the current view controller to the specified asset ID. The method calls the AssetTracking.shared.bindAsset() method to make the API request.

  4. saveAssetProfile(): This method saves the asset profile to the user's device. The method updates the values of the customId, assetName, assetDescription, assetAttributes, and assetId properties, and then calls the userDefaults.set() method to save the values to the user's device.

  5. onCreateAssetTapped(): This method is called when the user taps on the create asset button. The method checks if the asset name is empty, and if it is, it displays a toast message. Otherwise, it creates a new asset and saves the asset profile.

  6. onBindAssetTapped(): This method is called when the user taps on the bind asset button. The method checks if the asset ID is empty, and if it is, it displays a toast message. Otherwise, it binds the current view controller to the asset and saves the asset profile.

  7. dismissKeyboard(): This method dismisses the keyboard. The method calls the view.endEditing(true) method to dismiss the keyboard.

Here is a more detailed explanation of some of the key concepts in the code:

  1. UITextFieldDelegate: This protocol is adopted by classes that want to receive notifications when a text field changes.

  2. UIGestureRecognizerDelegate: This protocol is adopted by classes that want to receive notifications when a gesture recognizer is triggered.

  3. AssetTrackingApiExceptionType: This enum defines the possible types of errors that can occur when calling the Asset Tracking API.

The ViewController class inherits from the UIViewController class, which is the base class for all view controllers in iOS.

  1. The class has several outlet properties: locationInfo, trackingStatus, trackingModeSelector, startTracking, stopTracking, createAsset, and vie**wDataLogs. These properties are linked to the corresponding UI elements in the view controller's storyboard.

  2. startTracking(): This method starts tracking the asset. The method calls the assetTracking.startTracking() method.

  3. stopTracking(): This method stops tracking the asset. The method calls the assetTracking.stopTracking() method.

  4. onTrackingStart(): This method is called when tracking starts. The method updates the trackingStatus label.

  5. onTrackingStop(): This method is called when tracking stops. The method updates the trackingStatus label.

  6. onLocationSuccess(): This method is called when a new location is received. The method updates the locationInfo label.

  7. onLocationFailure(): This method is called when an error occurs while getting the location. The method does nothing in this case.

  8. onLocationServiceOff(): This method is called when location services are turned off. The method displays an alert to the user.

Here is a more detailed explanation of some of the key concepts in the code:

  1. AssetTracking: This class is responsible for tracking assets.

  2. TrackingMode: This enum defines the three possible tracking modes: ACTIVE, BALANCED, and PASSIVE.

  3. TrackingDisableType: This enum defines the possible reasons why tracking was stopped.

  4. CLLocation: This class represents a location on Earth.

  5. UIAlertController: This class is used to display alerts.

DIDN'T FIND WHAT YOU LOOKING FOR?