Mode Background iOS
Bài đăng này đã không được cập nhật trong 3 năm
Các ứng dụng chạy trên nền iOS hầu như sẽ bị dừng lại khi bạn bấm nút "Home" hoặc bạn chuyển sang chạy một ứng dụng khác, mặc dù nó vẫn còn tồn tại trong bộ nhớ nhưng nó sẽ không chạy bất cứ đoạn mã nào cho đến khi người dùng bật nó lên một lần nữa. Tuy nhiên trong một số trường hợp cụ thể ứng dụng của bạn có thể tiếp tục chạy các đoạn mã trong chế độ nền. Như bạn đã biết Apple nổi tiếng nhờ sự khó tính và khắc khe với các nhà phát triển ứng dụng do đó các trường hợp chạy ở chế độ nền cũng được Apple quy định rất cụ thể.
- Ứng dựng chơi nhạc
- Ứng dụng cập nhật vị trí
- Ứng dụng push notification
- Ứng dụng chạy trong quầy báo (Newsstand)
- Ứng dụng chạy nền với thời gian hữu hạn
- Ứng dụng VoIP
Sau đây tôi sẽ giới thiệu 2 trường hợp iOS cho phép ứng dụng của bạn chạy trong nền của nó là cập nhật vị trí và nhận push notification.
Push notification
Tôi sẽ demo 1 ví dụ update 1 ảnh khi app đang ở chế độ nền nếu nhận được push. Để chạy được push thì bạn có thể dùng file php và pem tôi đính kèm ở cuối
Tạo new project
Sửa file plist như hình sau
Click vào project và chọn Capabilities/Background modes và tích vào Remote Notification
Trong Appdelegate -> didFinishLaunchingWithOptions thêm dòng code đăng ký push notification
UIApplication.sharedApplication().registerForRemoteNotificationTypes( [.Alert, .Badge, .Sound])
Trong Appdelegate thêm hàm didRegisterForRemoteNotificationsWithDeviceToken để lấy device token, bạn hãy thay device token này vào file push_dev.php.
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let replacing1 = deviceToken.description.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
let replacing2 = replacing1.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
let replacing3 = replacing2.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
let deviceTokenString: NSString = replacing3.stringByReplacingOccurrencesOfString(" ", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
NSLog("------Device_Token-----> %@", deviceTokenString);
}
Trong Appdelegate thêm hàm lắng nghe khi có remote notification, trong hàm này sẽ lấy được tên file ảnh trả về và cập nhật lại view.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
if application.applicationState == UIApplicationState.Background {
print("didReceiveRemoteNotification-->UIBackgroundFetchResult")
print(userInfo.description)
//get image url from payload
if let apsData = userInfo["aps"] as? NSDictionary {
if let imageUrl = apsData["image_url"] as? String {
imageViewController.setImage(imageUrl)
}
}
}
completionHandler(.NewData)
}
link source: https://github.com/phanthanhhai/push_notification_background
update current location
Tôi sẽ demo 1 ví dụ app khi đang ở chế độ nền sẽ liên tục cập nhật vị trí hiện tại và push local về máy. Tạo 1 project mới
Click vào project và chọn Capabilities/Background modes và tích vào Remote Notification
Thêm key NSLocationAlwaysUsageDescription cho plist file
Thêm đoạn code sau để lấy location
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
locationManager?.startUpdatingLocation()
locationManager?.requestAlwaysAuthorization()
if( CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){
let currentLocation = locationManager?.location
longtitudeLb.text = "\(currentLocation!.coordinate.longitude)"
latitudeLb.text = "\(currentLocation!.coordinate.latitude)"
}
Thêm 2 delegates sau để lắng nghe khi có thông tin vị trí gửi về
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error while updating location " + error.localizedDescription)
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if (error != nil) {
print("Reverse geocoder failed with error" + error.localizedDescription)
return
}
if placemarks.count > 0 {
let pm = placemarks[0] as? CLPlacemark
self.displayLocationInfo(pm)
} else {
print("Problem with the data received from geocoder")
}
})
}
Khi nhận được vị trí thì push local để nhắc
func displayLocationInfo(placemark: CLPlacemark?) {
if placemark != nil {
// stop updating location to save battery life
// locationManager?.stopUpdatingLocation()
print(placemark!.locality)
print(placemark!.postalCode)
print(placemark!.administrativeArea)
print(placemark!.country)
self.pushLocalTouched()
}
}
func pushLocalTouched() {
let notification = UILocalNotification()
notification.alertBody = "New location" // text that will be displayed in the notification
notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
notification.fireDate = NSDate(timeIntervalSinceNow: 3)
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
notification.userInfo = ["UUID": "aaaaaaaa", ] // assign a unique identifier to the notification so that we can retrieve it later
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
link source: https://github.com/phanthanhhai/location_background
Thank you!
All rights reserved