Author: conmeotrongngo

  • Chọn FileOwner hay Custom class khi tạo một Custom UIView

    Chọn FileOwner hay Custom class khi tạo một Custom UIView

    Thông thường chúng ta có 3 cách dùng khi tạo 1 file custom UIView. Chúng ta hãy cùng làm theo cả 3 cách sau đây để xem ưu, nhược điểm của từng cái nhé.

    A. Set File owner

    B. Set Custom class

    C. Set cả hai File owner và Custom class

    Giờ hãy tạo 1 Tabbar Controller chứa 3 view controller để thực hành add custom view theo 3 cách trên nhé.

    Cách A. Thêm custom view dùng File owner

    – Trước hết, ta cần hiểu FIleOwner là gì? File owner là một controller object giúp ta kết nối code với các elements, UI trong file nib. 

    • Bước 1: Tạo file xib và class “CustomViewA”

    Views có thể được tạo bằng hai cách: 

    + Tạo view bằng code, ta gọi hàm init(frame: CGRect)

    + Nếu dùng file nib, khi file nib được load sẽ gọi hàm  init?(coder: NSCoder) 

    Nếu muốn support cả 2 cách, ta implement cả 2 hàm trên

    Ở ví dụ này ta tạo custom view bằng cách dùng file xib chứ không dùng code

    Tạo file xib CustomViewA.xib

    Tạo file CustomViewA.swift. Ở file CustomViewA.swift, ta setup code như sau:

    import UIKit
    
    final class CustomViewA: UIView {
        override init(frame: CGRect) {
            super.init(frame: frame)
            initView()
        }
        
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            initView()
        }
        
        private func initView() {
            // Để load file nib, ta tạo một instance của UINib
            // Ta set bundle là nil để dùng bundle default
            let nib = UINib(nibName: "CustomViewA", bundle: nil)
            
            // Khởi tạo contents trong file nib, objects là 1 array của tất cả top-level objects trong file nibs
            let objects = nib.instantiate(withOwner: self, options: nil)
            
            // Lưu ý: Vì list object trả ra từ file nib chưa thuộc view hierarchy nào nên ta phải addSubview vào CustomViewA
            if let view = objects.first as? UIView {
                view.backgroundColor = .clear
                addSubview(view)
                view.frame = bounds
                view.backgroundColor = .orange
            }
        }
    }
    • Bước 2: Set class cho file owner

    Mở file xib, chọn File’s Owner, rồi set Custom class là “CustomViewA” vừa tạo

    • Bước 3: Mở “ViewControllerA” trong storyboard, kéo một view vào rồi set Custom Class cho nó là “CustomViewA”.

    Chạy app và ta đã tạo được một custom view, kết quả như hình bên dưới.

    Cách B. Thêm custom view dùng Custom Class

    • Bước 1:

    Tạo file CustomViewB giống file CustomViewA như ở cách A

    • Bước 2:

    Thay vì FileOwner như cách A, ta chọn View ở dưới, rồi set Custom Class là “CustomViewB

    • Bước 3: Ta cũng kéo view “CustomViewB” vừa tạo vào ViewControllerB như bước 3 cách A, rồi chạy app

    Oops!!! Cách này dùng thì lại bị crash. Tại sao lại thế???

    Lý do vì khi load ViewControllerB, app sẽ call  “init?(coder: NSCoder)” của custom view (CustomViewB), tiếp theo sẽ call  “initView()“. Trong hàm này ta dùng “instantiate(withOwner)” để load file Nib.

    Tuy nhiên, vì ở bước 2 ta đã set top-level view của file nib là class CustomViewB nên nó sẽ load lại file nib và call hàm “init?(coder: NSCoder)” một lần nữa. Cứ thế nó sẽ tạo 1 vòng loop vô hạn khiến app bị crash.

    Để tránh trường hợp này, ta bỏ hàm “initView()” ra ngoài, không để trong “init?(coder: NSCoder)” or “init(frame: CGRect)” nữa.

    • Bước 4: Move hàm load xib ra bên ngoài View Controller (parent view controller)
    import UIKit
    
    class ViewControllerB: UIViewController {
        
        var viewCustomB: CustomViewB!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            initView()
        }
        
        private func initView() {
            let nib = UINib(nibName: "CustomViewB", bundle: nil)
            let objects = nib.instantiate(withOwner: nil, options: nil)
    
            if let firstView = objects.first as? CustomViewB {
                firstView.backgroundColor = .red
                viewCustomB = firstView
                view.addSubview(viewCustomB)
                viewCustomB.translatesAutoresizingMaskIntoConstraints = false
                viewCustomB.widthAnchor.constraint(equalToConstant: 240).isActive = true
                viewCustomB.heightAnchor.constraint(equalTo: viewCustomB.widthAnchor).isActive = true
                viewCustomB.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
                viewCustomB.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
            }
        }
    }

    Chạy app và ta đã tạo được một custom view, kết quả như hình bên dưới.

    Như vậy ta vẫn có thể add custom view bằng cách B này, nhưng nó có nhược điểm:

    • Ta sẽ phải load file nib (CustomViewB.xib) mọi nơi mà ta muốn dùng nó và sẽ gây ra duplicate code.

    Cách C. Thêm custom view dùng Custom Class và FileOwner

    • Bước 1: Tạo file CustomViewC.swift và CustomViewC.xib giống file CustomViewA như ở cách A
    • Bước 2: Tạo 1 button ở giữa view
    • Bước 3: Lần này, ta set CustomClass của view là “CustomViewC”, còn set FileOwner là parent class của nó (ViewControllerC)
    • Bước 4: Để logic load file xib ở parent class (để tránh crash như cách B) và kéo IBAction của button vào cả parent và custom view class

    Khi tap button, ta thấy debug đều chỉ ra cùng là một object.

    ==> Ok vậy ta đã thử qua 3 cách để tạo một custom view, ta có thể thấy rằng cách A đầu tiên dùng FileOwner là tiện lợi nhất

    • Dễ reuse trong toàn app thông qua code, xib hoặc storyboards
    • Không dính crash, tránh duplicate code như cách B

    Sau đây là một số tip mà các bạn chắc cũng đã biết =)))

    Tip1: Ở trong file xib, bạn có thể chọn Size “Freeform” trong Attribute Inspector để resize view

    Tip2: Trong cách A, ta có thể tạo một outlet contentView là top-level view của file xib, từ đó không cần phải get first object khi instantiate xib file nữa.

    Bài viết có tham khảo nguồn từ 2 link dưới đây, ở đó họ sẽ giải thích chi tiết view là gì, được khởi tạo như thế nào, file nib là gì, cách dùng customview bằng code hoặc file nib…

    https://github.com/codepath/ios_guides/wiki/Custom-Views#how-views-are-defined-and-instantiated

    https://medium.com/@bhupendra.trivedi14/understanding-custom-uiview-in-depth-setting-file-owner-vs-custom-class-e2cab4bb9df8

    Code: https://github.com/sonvuhwg/AddCustomView

    Have a nice day!

  • Hướng dẫn tạo và sử dụng Manually Signing App

    Hướng dẫn tạo và sử dụng Manually Signing App

    Link tham khảo: https://help.apple.com/developer-account/

    Code Signing là một thứ bắt buộc để ta có thể cài đặt ứng dụng vào devices thật, hoặc để upload lên AppStore Connect. Có hai cách để cài đặt code signing, “Automatically manage signing” hoặc “Manually manage signing”. Bài viết này sẽ hướng dẫn cài đặt manual code signing.

    Để cài đặt app, bạn cần có :

    • Signing certificate (Personal Information Exchange, .p12)
    • Provisioning profile (.mobileprovision)

    Signing certificate là chứng chỉ giúp xác định danh tính để cài app

    Provision profile (development hoặc distribution) chứa những thông tin về appID, các devices mà app có thể cài đặt, thông tin certificate để signing app. Lưu ý rằng nếu ứng dụng có chứa các extensions, bạn cần thêm các provision profile tương ứng 

    Mỗi dự án sẽ có những certificate và provision profile riêng. Như ảnh dưới, ta có 2 certificate, cho môi trường dev và distribute, ta cũng có các provision dev và distribute tương ứng, kèm theo đó là những provision profile của các extension của app.

    Sau đây là hướng dẫn tạo manually signing app:

    B1. Tạo certificate cho app

    1. Ở Certificates, Identifiers & Profiles, chọn Certificates

    2. Chọn nút (+)

    3. Chọn loại certificates mà mình muốn và chọn nút “Tiếp tục”

    4. Tạo certificate signing request

    4.1. Mở app Keychain Access ở máy

    4.2. Chọn Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority. 

    4.3. Điền thông tin như email, name, bổ trống CA Email Address

    4.4. Chọn “Save to disk” và chọn tiếp tục

    5. Chọn file đuôi .certSigningRequest đã tạo ở b4

    6. Chọn “Tiếp tục” và “Tải về” máy. (File certificate sẽ có đuôi .cer)

    B2. Đăng ký AppID

    AppID sẽ định danh app của bạn trong provisioning profile. Có 2 loại AppID: explicit AppID (sử dụng riêng từng app) và wildcard AppID (sử dụng chung 1 số app). Wildcard AppID sẽ chỉ enable được một số Capabilities, nếu muốn sử dụng những Capabilities khác, bạn phải tạo explicit AppID

    Các bước tạo AppID:

    1. Trong Certificates, Identifiers & Profiles, chọn “Identifiers”, rồi chọn (+)
    2. Chọn AppIDs 
    3. Điền name, descriptions, chọn các loại Capabilities mà app sẽ dùng
    • Nếu chọn Explicit App ID, bạn phải điền giống bundleID của app trong Xcode
    • Nếu chọn Wildcard App ID, bạn phải điền bundle ID với hậu tố (VD: com.domainname.*)

    B3. Đăng ký devices

    Đăng ký một device:

    1. Trong Certificates, Identifiers & Profiles, chọn Devices, rồi chọn (+)
    2. Chọn platform, điền device name, device ID (UDID)
    3. Chọn tiếp tục, chọn “Register” để hoàn tất đăng ký

    Đăng ký nhiều device:

    Bạn có thể dùng app “Configurator 2” trên MacAppStore hoặc tạo file .txt chứa thông tin (mỗi dòng chứa deviceID, device name, platform name cách nhau bởi tab-delimited)

    B4. Tạo provisioning profile

    1. Trong Certificates, Identifiers & Profiles, chọn Profiles, rồi chọn nút (+) 
    2. Chọn loại provisioning profile mà bạn muốn tạo, rồi chọn “Tiếp tục”

    3. Chọn App ID mà mình đã tạo ở Bước 2, chọn “Tiếp tục”

    4. Chọn Certificate mà mình đã tạo ở Bước 1, chọn “Tiếp tục”

    5. Chọn các device đã được tạo ở Bước 3, chọn “Tiếp tục”

    6. Điền profile name, rồi chọn “Generate”

    7. Chọn “Download” để tải về

    8. Sau khi đã tải về, click double vào các certificate và nhập mật khẩu để add vào keychain

    • Tắt Automatically manage signing trong Xcode 
    • Import các provision profile tương ứng 

    Nếu status không còn báo đỏ nữa là bạn đã import thành công. Giờ run và build thôi.

  • Push Notification trên iOS Simulator

    Push Notification trên iOS Simulator

    Như các bạn đã biết, để dùng APNS (Apple Push Notification service) thì chúng ta cần phải có device thật. Nhưng chuyện đó đã là quá khứ khi ở bản 11.4 beta, Apple đã cho phép test push notification ngay trên simulator. Tuyệt vời !!! ?

    Để có thể push notification trên simulator, bạn cần:
    Bước 1: Tải Xcode 11.4 beta hoặc các phiên bản mới hơn tại link nè: https://developer.apple.com/download/

    Bước 2: Tạo project và grant permission 
    Appdelegate.swift, import framework UserNotifications, và yêu cầu quyền nhận notification ở hàm application(_:didFinishLaunchingWithOptions:)

    Bước 3: Tạo file APNS payload
    APNS payload là một file json dictionary chứa đựng các thông tin của Notification như kiểu thông báo, nội dung thông báo… Bạn có thể vào đây để xem thêm chi tiết:
    https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification

    Mình tạo file payload thêm 1 key “Simulator Target Bundle” như sau:

    Trong đó “yourBundleID” là bundleID app của bạn, bundle project của mình là “com.self.NotificationSimulator

    Bước 4:  Giờ kéo thả vào simulator thôi!
    Giờ bạn hãy kéo file payload vừa tạo vào simulator, xem điều kì diệu gì xảy ra nhé 

    Simulator đã có notification ?

    Ngoài cách kéo thả file APNS vào Simulator, ta còn có thể dùng câu lệnh Command để gửi noti. Ở Xcode 11.4 này đã có thêm command xcrun simctl push hỗ trợ việc bắn notification.

    xcrun simctl push <simulator-identifier> <path-to-payload-file>

    trong đó <simulator-identifier> là ID của simulator, <path-to-payload-file> là đường dẫn đến file payload. Bạn có thể lấy ID simulator như sau:

    Nếu bạn ngại việc copy identifier, bạn có thể dùng xcrun simctl push booted <path-to-payload-file> để push notification ngay trên simulator đang mở. Và kết quả:

    Kết luận

    Giờ đây ta có thể test push notification thật đơn giản trên simulator. Ta có 2 cách để test:
    – Kéo thả file APNS vào simulator
    – Trỏ đường dẫn file APNS hoặc Json payload qua command line
    Sau bài viết này, mình sẽ giới thiệu các bạn về Leanplum – một marketing platform cho mobile, và xem điểm giống và khác nhau giữa Leanplum vs Firebase nhé

    Nguồn: https://swiftsenpai.com/xcode/simulating-push-notifications-in-ios-simulator/