How to deal with multiple scenarios with Push Notification in iOS

Issue #459 Here are my notes when working with Push Notification How to register Register to receive push notification registerForRemoteNotificationTypes is deprecated in iOS 8+ UIApplication.sharedApplication().registerForRemoteNotifications() Register to alert user through UI If your app displays alerts, play sounds, or badges its icon, you must call this method during your launch cycle to request permission to alert the user in these ways let types: UIUserNotificationType = [.Badge, .Sound, ....

October 11, 2019 · 6 min · Khoa Pham

How to use Apple certificate in Xcode 11

Issue #458 For push notification, we can now use just Production Certificate for 2 environments (production and sandbox) instead of Development and Production certificates. Now for code signing, with Xcode 11 https://developer.apple.com/documentation/xcode_release_notes/xcode_11_release_notes we can just use Apple Development and Apple Distribution certificate for multiple platforms Signing and capabilities settings are now combined within a new Signing & Capabilities tab in the Project Editor. The new tab enables using different app capabilities across multiple build configurations....

October 11, 2019 · 1 min · Khoa Pham

How to use provisional notification in iOS 12

Issue #456 From WWDC 2018 What’s New in User Notifications Instead, the notifications from your app will automatically start getting delivered. Notifications that are delivered with provisional authorization will have a prompt like this on the notification itself. And this will help the users decide after having received a few notifications whether they want to keep getting these notifications or whether they want to turn them off...

October 10, 2019 · 2 min · Khoa Pham

How to check if push notification is actually enabled in iOS

Issue #455 There are times we want to log if user can receive push notification. We may be tempted to merely use isRegisteredForRemoteNotifications but that is not enough. From a user ’s point of view, they can either receive push notification or not. But behind the scene, many factors are in the game. It can be that user has disabled push notification in app settings or in iOS Settings. It can also be that user enables push notification but disables all sound or banner display mechanism....

October 10, 2019 · 2 min · Khoa Pham

How to use UserNotificationsUI in iOS

Issue #454 From documentation https://developer.apple.com/documentation/usernotificationsui Customize how local and remote notifications appear on the user’s device by adding a notification content app extension to the bundle of your iOS app. Your extension manages a custom view controller, which you use to present the content from incoming notifications. When a notification arrives, the system displays your view controller in addition to, or in place of, the default system interface. https://developer....

October 10, 2019 · 1 min · Khoa Pham

How to register for alert push notification in iOS

Issue #452 Use UserNotifications framework import FirebaseMessaging import UserNotifications final class PushHandler: NSObject { private let center = UNUserNotificationCenter.current() private let options: UNAuthorizationOptions = [.alert] func setup() { Messaging.messaging().delegate = self } func register() { center.requestAuthorization(options: options, completionHandler: { granted, error in print(granted, error) self.getSettings() }) } func getSettings() { center.getNotificationSettings(completionHandler: { settings in guard case let .authorized = settings.authorizationStatus, case let .enabled = settings.alertSetting, settings.alertStyle != .none else { return } // TODO }) } func handle(userInfo: [AnyHashable: Any]) { } } extension PushHandler: MessagingDelegate { func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { print(fcmToken) } func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) { print(remoteMessage) } } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { completionHandler(....

October 10, 2019 · 1 min · Khoa Pham

How to fix unreadable ASCII characters in Swift

Issue #444 To avoid compiler error Unprintable ASCII character found in source file, from Swift 5, we can use isASCII. Run this from the generator app that generates Swift code. let normalized = weirdString.filter({ $0.isASCII }) For more check, see Character https://developer.apple.com/documentation/swift/character/3127011-isletter Watch out for Delete/House symbol ⌂ code 127 (0x7f) The above does not seem to work, use find to find  character (copy Sublime Text to see 0x7f character)...

October 7, 2019 · 1 min · Khoa Pham

How to get url of app on the iOS AppStore

Issue #440 http://itunes.apple.com/[country]/app/[App–Name]/id[App-ID]?mt=8 For example https://apps.apple.com/nl/app/cutters/id1466739130

October 3, 2019 · 1 min · Khoa Pham

How to handle UICollectionView reloadData with selected index path

Issue #434 When calling collectionView.reloadData(), selected indexpath stays the same, but be aware that order of data may have changed let selectedData = ... let indexPathForSelectedData = ... collectionView.scrollToItem( at: indexPathForSelectedData, at: .centeredHorizontally, animated: false )

September 30, 2019 · 1 min · Khoa Pham

How to use Firebase ID token

Issue #424 https://medium.com/@jwngr/demystifying-firebase-auth-tokens-e0c533ed330c One confusing point here that people often do not realize is that even though the custom token itself expires after one hour, a modern client SDK authenticated with that custom token will stay authenticated beyond that hour! What happens under the hood is that the custom token is sent to the Firebase Auth service in exchange for an ID token and refresh token pair which are used to keep the client SDK authenticated...

September 17, 2019 · 2 min · Khoa Pham

How to constrain to views inside UICollectionViewCell in iOS

Issue #422 To constrain views outside to elements inside UICollectionViewCell, we can use UILayoutGuide. Need to make layout guide the same constraints as the real elements let imageViewGuide = UILayoutGuide() collectionView.addLayoutGuide(imageViewGuide) NSLayoutConstraint.on([ imageViewGuide.topAnchor.constraint(equalTo: collectionView.topAnchor, constant: 16), imageViewGuide.heightAnchor.constraint(equalTo: collectionView.heightAnchor, multiplier: 0.5) ]) NSLayoutConstraint.on([ loadingIndicator.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor), loadingIndicator.centerYAnchor.constraint(equalTo: imageViewGuide.centerYAnchor) ])

September 17, 2019 · 1 min · Khoa Pham

How to secure CVC in STPPaymentCardTextField in Stripe for iOS

Issue #421 private func maskCvcIfAny() { guard let view = paymentTextField.subviews.first(where: { !($0 is UIImageView) }), let cvcField = view.subviews .compactMap({ $0 as? UITextField }) .first(where: { $0.tag == 2 && ($0.accessibilityLabel ?? "").lowercased().contains("cvc") }) else { return } cvcField.isSecureTextEntry = true } where tag is in STPPaymentCardTextFieldViewModel.h typedef NS_ENUM(NSInteger, STPCardFieldType) { STPCardFieldTypeNumber, STPCardFieldTypeExpiration, STPCardFieldTypeCVC, STPCardFieldTypePostalCode, }; Also, need to check accessibilityLabel in STPPaymentCardTextField.m - (NSString *)defaultCVCPlaceholder { if (self.viewModel.brand == STPCardBrandAmex) { return STPLocalizedString(@"CVV", @"Label for entering CVV in text field"); } else { return STPLocalizedString(@"CVC", @"Label for entering CVC in text field"); } }

September 16, 2019 · 1 min · Khoa Pham

How to easily parse deep json in Swift

Issue #414 Codable is awesome, but sometimes we just need to quickly get value in a deepy nested JSON. In the same way I did for Dart How to resolve deep json object in Dart, let’s make that in Swift. See https://github.com/onmyway133/Omnia/blob/master/Sources/Shared/JSON.swift public func resolve<T>(_ jsonDictionary: [String: Any], keyPath: String) -> T? { var current: Any? = jsonDictionary keyPath.split(separator: ".").forEach { component in if let maybeInt = Int(component), let array = current as?...

September 12, 2019 · 1 min · Khoa Pham

How to speed up GMSMarker in Google Maps for iOS

Issue #412 Google Maps with a lot of pin, and no clustering can have bad performance if there are complex view in the marker. The workaround is to use manual layout and rasterization shouldRasterize When the value of this property is true, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content. Shadow effects and any filters in the filters property are rasterized and included in the bitmap....

September 10, 2019 · 2 min · Khoa Pham

How to support drag and drop in UICollectionView iOS

Issue #411 See DragAndDrop example class ViewController: UIViewController, UICollectionViewDropDelegate, UICollectionViewDragDelegate { // MARK:- UICollectionViewDragDelegate func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { let controller = leftController let provider = NSItemProvider( object: controller.imageForCell(indexPath: indexPath) ) let dragItem = UIDragItem(itemProvider: provider) dragItem.localObject = indexPath return [dragItem] } // MARK:- UICollectionViewDropDelegate func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { let destinationIndexPath: IndexPath if let indexPath = coordinator.destinationIndexPath { destinationIndexPath = indexPath } else { destinationIndexPath = IndexPath(row: 0, section: 0) } let controller = rightController let dragItemIndexPath = coordinator....

September 10, 2019 · 1 min · Khoa Pham

How to test Date with timezone aware in Swift

Issue #402 I want to test if a date has passed another date let base = Date(timeIntervalSince1970: 1567756697) XCTAssertEqual(validator.hasPassed(event: event, date: base), true) My hasPassed is using Calendar.current func minuteSinceMidnight(date: Date) -> MinuteSinceMidnight { let calendar = Calendar.current let start = calendar.startOfDay(for: date) return Int(date.timeIntervalSince(start)) / 60 } But the minute is always having timezone applied. Even if I try with DateComponents func minuteSinceMidnight(date: Date) -> MinuteSinceMidnight { let components = calendar....

September 6, 2019 · 2 min · Khoa Pham

How to do simple analytics in iOS

Issue #395 Prefer static enum to avoid repetition and error. The Log should have methods with all required fields so the call site is as simple as possible. How to format and assign parameters is encapsulated in this Analytics. import Foundation import Firebase import FirebaseAnalytics struct Analytics { enum Parameter: String { case studentId = "student_id" case classId = "class_id" case url = "url" } enum Property: String { case grantLocation = "grant_location" } enum Name: String { case login case logOut = "log_out" case enroll } struct Log { private func log(_ name: Name, parameters: [Parameter: String] = [:]) { let mapped: [String: String] = Dictionary(uniqueKeysWithValues: parameters....

September 4, 2019 · 1 min · Khoa Pham

How to choose Firebase vs Google Analytics

Issue #387 Google Analytics is shutting down. From Firebase Analytics console, we can choose to upgrade to Google Analytics, no code change is needed. https://support.google.com/firebase/answer/9167112?hl=en In October 2019, we will start to sunset Google Analytics mobile-apps reporting based on the Google Analytics Services SDKs for Android and iOS. https://firebase.googleblog.com/2019/07/firebase-google-analytics-upgrade.html Thanks to our continued partnership with Google Analytics, you can now upgrade your Firebase projects to the next generation of app analytics!...

September 3, 2019 · 1 min · Khoa Pham

How to use lessThan and greaterThan in Auto Layout in iOS

Issue #386 When it comes to right and bottom side, we should use negative values, and use lessThan, as it means less than a negative value

September 3, 2019 · 1 min · Khoa Pham

How to check app running on jailbreak iOS device

Issue #385 From https://github.com/OneSignal/OneSignal-iOS-SDK/blob/master/iOS_SDK/OneSignalSDK/Source/OneSignalJailbreakDetection.m + (BOOL)isJailbroken { #if !(TARGET_IPHONE_SIMULATOR) FILE *file = fopen("/Applications/Cydia.app", "r"); if (file) { fclose(file); return YES; } file = fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r"); if (file) { fclose(file); return YES; } file = fopen("/bin/bash", "r"); if (file) { fclose(file); return YES; } file = fopen("/usr/sbin/sshd", "r"); if (file) { fclose(file); return YES; } file = fopen("/etc/apt", "r"); if (file) { fclose(file); return YES; } file = fopen("/usr/bin/ssh", "r"); if (file) { fclose(file); return YES; } NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:@"/Applications/Cydia....

September 2, 2019 · 1 min · Khoa Pham