Thông thường thì các ứng dụng phát triển càng lâu thì tính năng của nó sẽ càng nhiều, điều này cũng làm cho khối lượng source code và Unit Test cũng tăng theo, có một số dự án xây dựng theo mô hình module hoá, khi này sẽ có rất nhiều module trong dự án cần thực hiện test nếu chúng ta chạy tất cả các file của project thì nó sẽ tốn rất nhiều thời gian, làm giảm đi năng suất làm việc của bản thân. Vì vậy để thực hiện các test case một cách nhanh chóng và hiệu quả Xcode cho phép chúng ta tự tạo Test Plan theo đúng kế hoạch mà chúng ta muốn. Chúng ta có thể tạo một test plan để test một màn hình riêng biệt cho đến hàng trăm màn hình hoặc có thể là một module mà chúng ta đang làm hay tất cả test case của ứng dụng.
Tạo mới Test Plan
Để tạo mới Test Plan ta làm theo các bước như sau:
Tạo mới test plan
Đặt tên cho test plan, bạn có thể đặt tên tuỳ ý miễn sao nó đúng với ý nghĩa là được. Sau đó bấm “Create” để Xcode thực hiện.
Sau khi tạo xong, test plan mới tạo sẽ được thêm vào danh sách, bạn có thể kiểm tra bằng cách thao tác như hình phía dưới đây
Để thực hiện cấu hình cho test plan mới này chúng ta bấm vào Edit Test Plan ở trên hình.
Do test plan mới được tạo nên bạn sẽ thấy nó trống, lúc này chưa có một file/class/module/target nào được thêm vào để test nên chúng ta cần thêm nó vào bằng cách bấm vào dấu + trên màn hình dưới đây:
Tương tự nếu bạn muốn loại bỏ một target nào thì ta có thể bấm dấu – để xoá khỏi test plan.
Chọn target mà bạn muốn thêm vào test plan và bấm “Add” để thêm target vào test plan.
Xcode sẽ thêm tất cả các file test chúng ta đã viết vào trong mục Tests, ở đây bạn sẽ nhìn thấy tất cả các file test mà bạn viết, bạn có thể bỏ tích một func hay 1 file để Xcode không chạy phần đó khi run test plan của bạn.
Để khi chạy test chúng ta xem được Code Coverage thì chúng ta cần đổi giá trị Code Coverage bên Configurations sang ON
Lúc này khi chạy Test Plan này chúng ta sẽ xem được kết quả bằng cách Report Navigator -> Local -> Test -> Coverage
Dựa vào báo cáo này bạn sẽ biết được bạn đã viết test case chạy qua được bao nhiêu phần trăm của source code từ đó bạn sẽ có thể đưa ra các action phù hợp.
Lưu ý Code Coverage chỉ là con số chỉ ra rằng source code test case của bạn đã chạy qua bao nhiêu dòng code, chứ nó không phải là chỉ số đảm bảo độ tin cậy source code của bạn. Vì vậy nó chỉ là điều kiện đủ, code coverage càng cao thì điều đó chứng tỏ Test Case của bạn đã chạy qua càng nhiều dòng code. Để đảm bảo chất lượng source code thì các bạn cần có một chút tư duy về testing, biết xác định các cặp input và output để thực hiện test, cần xác định các điều kiện biên, ngoại lệ, trường hợp lỗi, trường hợp thành công …. thì việc viết test case mới có hiệu quả.
Bạn đang tìm một phương pháp để tăng chất lượng source code? Bạn đang gặp vấn đề về việc source code của bạn có quá nhiều bug? Unit tests là một trong những lựa chọn giúp bạn hạn chế vấn đề đó.
Hiện nay rất nhiều dự án yêu cầu viết Unit tests nhằm mục đích đảm bảo chất lượng source code, vì vậy bài viết này mình sẽ chia sẻ với các bạn về Unit Tests trong Swift để các bạn có thể trang bị cho mình được một kĩ năng mới, để có thể sẵn sàng và tự tin chiến các dự án hiện tại hoặc trong tương lai.
Unit Testing là gì?
Unit tests là tự động chạy và kiểm thử một đoạn mã để đảm bảo nó hoạt động đúng như dự định và đúng với tài liệu yêu cầu.
Unit tests trong ngôn ngữ lập trình là việc viết các func test để đảm bảo source code hoạt động đúng như tài liệu yêu cầu. Với một đầu vào cụ thể sẽ cho ra một đầu ra cụ thể như tài liệu yêu cầu. Việc viết Unit tests để kiểm tra source code của bạn giúp bạn tự tin hơn khi release hay tái cấu trúc source code, vì bạn sẽ đảm bảo source code của mình chạy đúng mong đợi khi bạn chạy bộ test case của bạn thành công.
Các quan điểm trái ngược về Unit tests
Hiện nay có rất nhiều quan điểm trái ngược nhau về việc một dự án có cần phải viết Unit Tests hay không? Rất nhiều Developer thì cho rằng việc viết test tốn quá nhiều thời gian nó làm ảnh hưởng tới việc bàn giao công việc đúng thời hạn. Một số Developer thì cho rằng việc viết Unit tests không đem lại quá nhiều lợi ích mà công việc lại lặp đi lặp lại quá nhàm chán. Tuy nhiên theo mình nếu bạn viết Unit tests đúng cách thì sẽ giúp bạn giảm được thời gian phát triển ứng dụng, tuy thời gian phát triển ban đầu có tăng thêm nhưng bạn sẽ giảm được số lượng bug cơ bản có thể xảy ra từ đó giảm thời gian fix bugs và hạn chế các lỗi phát sinh sau khi sửa.
Viết Unit Tests với Xcode
Để giúp các nhà phát triển có thể viết Unit Tests cho các ứng dụng của họ, Apple đã tạo ra XCTest framework. Giờ đây các nhà phát triển có thể sử dụng framework này đê viết Unit tests cũng như chạy các test case để kiểm tra chất lượng source code của họ.
Một số hàm dùng để kiểm tra của XCTest Framework
XCTAssert(): Nó khá thông dụng có thể sử dụng trong hầu hết các trường hợp, VD: XCTAssert(result == 5)
XCTAssertTrue(): test case của bạn sẽ pass nếu biểu thức kiểm tra có kết quả là true. VD: XCTAssertTrue(view.isHidden)
XCTAssertEqual(a, b), XCTAssertNotEqual: Kiểm tra xem giá trị của 2 biểu thức.
XCTAssertFalse(): ngược với XCTAssertTrue
XCTAssertGreaterThan(a, b): Thường dùng khi bạn kiểm tra 2 giá trị số
XCTAssertGreaterThanOrEqual(a, b): tương tự như XCTAssertGreaterThan, nếu 2 giá trị = nhau thì test case vẫn pass
XCTAssertLessThan, XCTAssertLessThanOrEqual: Tương tự như mục 5 và 6
XCTAssertNil(a), XCTAssertNotNil: Dùng khi cần kiểm tra một var/func có nil hay không
XCTAssertNoThrow() Dùng khi cần kiểm tra xem func có throw lỗi hay không
XCTAssertThrowsError() dùng khi cần kiểm tra func có throw error và kiểm tra được error
Để các bạn dễ hình dung hơn mình sẽ đưa ra một ví dụ như sau:
Tài liệu yêu cầu bạn phải viết một hàm để tính chu vi của hình chữ nhật khi biết chiều dài và chiều rộng của nó. Ta biết chu vi của hình chữ nhật chính là tổng tất cả các cạnh của nó, vì vậy ta có thể sẽ viết func như sau:
class Regtangle {
// hàm tính chu vi hình chữ nhật
class func perimeter(width: Int, height: Int) -> Int {
(width + height) * 2
}
}
Để viết bắt đầu viết test case chúng ta sẽ cần tạo file test như sau:
Chuột phải vào thư mục cần tạo file -> chọn new file -> Unit Test Case Class -> Next
Đặt tên cho file test, trong trường hợp này mình đang cần test class Regtangle nên mình đặt tên như hình -> Next
Sau khi tạo file chúng ta XCode sẽ tạo sẵn cho chúng ta một số đoạn code cơ bản như sau:
import XCTest
// thêm target cần test
@testable import UTXcode14
final class RegtangleTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// Any test you write for XCTest can be annotated as throws and async.
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
func testPerformanceExample() đây là hàm để kiểm tra hiệu suất của đoạn code, nếu bạn không cần kiểm tra thì bỏ nó đi giúp mỗi lần chạy test của bạn sẽ nhanh hơn đáng kể.
Bây giờ chúng ta đã có thể viết test case để kiêm tra class Regtangle. Đối với func tính chu vi như vậy thì ta sẽ cần dựa vào yêu cầu và phân tích tích bài toán một chút.
Chúng ta hiểu rằng chiều cao và chiều rộng của hình chữ nhật phải là số lớn hơn 0, chu vi của hình chữ nhật thì bằng tổng chiều dài bốn cạnh, vậy nên chúng ta sẽ cần viết các test case với trường hợp như sau:
width và height đều lớn hơn 0: Đầu ra là (width + height) * 2
width <= 0, height > 0: đầu ra cần phải là một thông báo lỗi
width > 0, height <= 0: Đầu ra cần phải là một thông báo lỗi
width <= 0, height <= 0: Đầu ra cần phải là một thông báo lỗi
Đối với case số 1 yêu cầu dữ liệu đầu vào cả width và height đều phải là một số > 0 thì ta viết như sau:
// case width > 0 and height > 0
func test_perimeter_case1() {
// input
let width: Int = 3
let height: Int = 2
// expectation
let expectation = 10
// run code
let result = Regtangle.perimeter(width: width, height: height)
// verify
XCTAssertEqual(result, expectation)
}
Chạy test ta thu đươc kết quả như hình, dấu tích xanh thể hiện kết quả với expectation là bằng nhau, có nghĩa là trong trường hợp này hàm Regtangle.perimeter() đã chạy đúng.
Tiếp theo chúng ta sẽ viết tiếp test case số 2, width <=0 và height > 0, đây là trường hợp chiều rộng nhỏ hơn 0 vì vậy nó là một trường hợp lỗi, mình sẽ mong đợi một thông báo lỗi “Width must be greater than zero”. Vậy nên mình viết code như hình dưới
Lúc này Xcode sẽ báo lỗi như hình trên là do chúng ta đang so sánh 2 kiểu dữ liệu khác nhau. Quay lại hàm tính chu vi hình chữ nhật thì chúng ta thấy không có logic kiểm tra width và height điều này khiến cho func này không đảm bảo tính đúng đắn của nó.
Vậy viết func tính chu vi như nào mới đúng? các bạn có thể tham khảo một số cách viết của mình như sau:
Cách 1: Sử dụng Result để trả về kết quả
// equatable để tiện cho việc so sánh khi viết Unit test
struct MyError: Error, Equatable {
let message: String
}
class Regtangle {
// hàm tính chu vi hình chữ nhật
class func perimeter(width: Int, height: Int) -> Result<Int, MyError> {
if width <= 0 && height <= 0 {
return .failure(MyError(message: "Width and height must be greater than zero"))
} else if width <= 0 {
return .failure(MyError(message: "Width must be greater than zero"))
} else if height <= 0 {
return .failure(MyError(message: "Height must be greater than zero"))
} else {
let perimeter = (width + height) * 2
return .success(perimeter)
}
}
}
Cách 2: Sử dụng throw để đẩy ra lỗi
struct MyError: Error, Equatable {
let message: String
}
class Regtangle {
// hàm tính chu vi hình chữ nhật
class func perimeter(width: Int, height: Int) throws -> Int {
if width <= 0 && height <= 0 {
throw MyError(message: "Width and height must be greater than zero")
} else if width <= 0 {
throw MyError(message: "Width must be greater than zero")
} else if height <= 0 {
throw MyError(message: "Height must be greater than zero")
} else {
return (width + height) * 2
}
}
}
Trong bài viết này mình sẽ hướng dẫn các bạn viết test case khi sử dụng throw, mình sẽ viết tổng cộng 7 test cases để thực hiện test func này, trong đó bao gồm 4 test cases để test logic chính và 3 cases để test giá trị biên. Cụ thể mình sẽ thực hiện như sau:
import XCTest
@testable import UTXcode14
final class RegtangleTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
// case width > 0 and height > 0
func test_perimeter_case1() throws {
// precontidtion
let width: Int = 3
let height: Int = 2
// expectation
let expectation = 10
// run code
XCTAssertNoThrow(try Regtangle.perimeter(width: width, height: height))
let result = try Regtangle.perimeter(width: width, height: height)
// verify
XCTAssertEqual(result, expectation)
}
// case width < 0 and height > 0
func test_perimeter_case2() throws {
// precontidtion
let width: Int = -3
let height: Int = 2
// expectation
let expectation = MyError(message: "Width must be greater than zero")
// run code
XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
XCTAssertEqual(error as? MyError, expectation)
}
}
// case width > 0 and height < 0
func test_perimeter_case3() throws {
// precontidtion
let width: Int = 3
let height: Int = -2
// expectation
let expectation = MyError(message: "Height must be greater than zero")
// run code
XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
XCTAssertEqual(error as? MyError, expectation)
}
}
// case width < 0 and height < 0
func test_perimeter_case4() throws {
// precontidtion
let width: Int = -3
let height: Int = -2
// expectation
let expectation = MyError(message: "Width and height must be greater than zero")
// run code
XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
XCTAssertEqual(error as? MyError, expectation)
}
}
// case width = 0 and height > 0, test giá trị biên của width
func test_perimeter_case5() throws {
// precontidtion
let width: Int = 0
let height: Int = 2
// expectation
let expectation = MyError(message: "Width must be greater than zero")
// run code
XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
XCTAssertEqual(error as? MyError, expectation)
}
}
// case width = 0 and height > 0, test giá trị biên của height
func test_perimeter_case6() throws {
// precontidtion
let width: Int = 2
let height: Int = 0
// expectation
let expectation = MyError(message: "Height must be greater than zero")
// run code
XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
XCTAssertEqual(error as? MyError, expectation)
}
}
// case width = 0 and height = 0, test giá trị biên của cả width và height
func test_perimeter_case7() throws {
// precontidtion
let width: Int = 0
let height: Int = 0
// expectation
let expectation = MyError(message: "Width and height must be greater than zero")
// run code
XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
XCTAssertEqual(error as? MyError, expectation)
}
}
}
Chạy test (Command U) chúng ta được kết quả như sau:
Tất cả các test case của chúng ta đều passed, điều này chứng minh func của bạn đã đáp ứng hết tất cả yêu cầu mà bạn đặt ra
Hi vọng bài viết sẽ giúp cho các bạn có thêm kiến thức để nâng cao năng lực của bản thân.
Hi, Ở phần 1 mình đã giới thiệu đến các bạn tổng quan về CP (CarPlay). Phần này mình sẽ chia sẻ cách để xây dựng một ứng dụng hỗ trợ CP, cụ thể ở đây là ứng dụng hỗ trợ một trong 8 CP types mà apple cung cấp, còn type Automaker thì mình chia sẻ mở bài tiếp theo.
Bắt đầu nào!!!
Tạo Project
Ứng dụng CP cũng là một ứng dụng bình thường, các bạn vẫn sử dụng xCode và tạo project như bình thường. Phần code của phone và CP sẽ là hai phần riêng biệt. Vì trên iPhone quá quen thuộc với các bạn rồi nên ở hướng dẫn này mình chỉ thực hiện hiển thị 1 dòng chữ ở giữa màn hình trên iPhone và tập chung vào việc hiển thị trên CP với các template
Tạo entitlement file
Như mình đề cập ở phần 1, với 8 type bình thường của Apple cung cấp thì đi kèm với nó là các entitlement key, thì key này sử dụng ở đâu?. Câu trả lời là key này sử dụng để config trong entitlement file.
Select file -> New file -> choose Property List
Điền tên file và chọn create
Ở đây mình để tên file là CPTemplateSeminar.entitlements
Sau khi tạo entitlement file thì chúng ta cần nhúng đường path dẫn đến entitlement file vào Code Signing Entitlements bằng cách chọn Project Setting -> Build Setting -> Code Signing Entitlements và set giá trị là path dẫn đến entitlement file
Tip: Ngoài cách tạo file và nhúng đường path như ở trên, các bạn có thể enable bất kì một Capabilities nào đó trong xCode để xCode tự động tạo ra entitlement file và tự động nhúng đường path vào Code Signing Entitlements
Sau khi setting Code Signing Entitlements xong, Chúng ta đến bước add entitlement key vào file vừa tạo. Ở đây mình sử dụng key com.apple.developer.carplay-audio. (Nếu các bạn chưa biết key này là gì và lấy ở đâu thì các bạn xem lại phần 1 của mình nhé!)
Implement Template
Tạo một class kế thừa CPTemplateApplicationSceneDelegate, delegate này có các methods như didConnect, didDisconnectInterfaceController …
Tất cả các CP app đều phải khai báo CP scene để dử dụng CP Framework. Để khai báo CP scene thì chúng ta khai báo ở trong info.plist
Khai báo thêm key CPTemplateApplicationSceneSessionRoleApplication theo như hướng dẫn dưới đây: Mình set UISceneConfigurationName là CarPlay, UISceneDelegateClassName là class mà mình đã tạo ở bên trên
Như một ứng dụng thông thường thì CP app cũng cần setup root view. Ở hướng dẫn này mình xây dựng CP app với root template là 1 tab bar bao gồm tab Home và tab Setting. Tab Home và Setting mình sẽ hiển thị list đơn giản
import Foundation
import CarPlay
// MARK: - Tab Template
extension CPSceneDelegate {
func createTabTemplate() -> CPTabBarTemplate {
var tabs: [CPTemplate] = []
let homeItem = CPListItem(text: "Home", detailText: "")
let homeSection = CPListSection(items: [homeItem])
let homeTemplate = CPListTemplate(title: "Home", sections: [homeSection])
homeTemplate.tabImage = UIImage(systemName: "house.fill")
let settingItem = CPListItem(text: "Setting", detailText: "")
let settingSection = CPListSection(items: [settingItem])
let settingTemplate = CPListTemplate(title: "Home", sections: [settingSection])
settingTemplate.tabImage = UIImage(systemName: "gearshape.fill")
tabs.append(homeTemplate)
tabs.append(settingTemplate)
let tabBar = CPTabBarTemplate(templates: tabs)
return tabBar
}
}
Mình tạo một tab bar bằng cách sử dụng CPTabBarTemplate, và mình set tab bar này thành root template khi iPhone và màn hình trên ô tô được kết nối.
Đến step này là đã hoàn thành việc coding một ứng dụng hỗ trợ CP rồi, Chúng ta có thể trải nghiệm ứng dụng bằng cách build lên simulator và sau đó mở cửa sổ xCode Simulator để xem thành quả. Tuy nhiên mình sẽ thêm phần action bấm vào item trên màn home và thực hiện di chuyển đến màn hình phát nhạc.
Tạo Now Playing template
import Foundation
import CarPlay
// MARK: - Playing now Template
extension CPSceneDelegate {
func createNowPlaying() -> CPNowPlayingTemplate {
let playing = CPNowPlayingTemplate.shared
playing.add(self)
playing.isUpNextButtonEnabled = true
playing.isAlbumArtistButtonEnabled = true
return playing
}
}
extension CPSceneDelegate: CPNowPlayingTemplateObserver {
func nowPlayingTemplateUpNextButtonTapped(_ nowPlayingTemplate: CPNowPlayingTemplate) {
}
func nowPlayingTemplateAlbumArtistButtonTapped(_ nowPlayingTemplate: CPNowPlayingTemplate) {
}
}
Thực hiện di chuyển khi bấm vào item trên màn hình Home. Mình sẽ thực hiện pushTemplate đến màn hình Now Playing được tạo bên trên, Các bạn có thể thực hiện push hoặc present tuỳ thích, tuy nhiên ở phần 1 mình cũng có warning là không phải template nào cũng có thể push và present được. Các bạn cứ thử thực hiện để trải nghiệm nhé!
import Foundation
import CarPlay
// MARK: - Tab Template
extension CPSceneDelegate {
func createTabTemplate() -> CPTabBarTemplate {
var tabs: [CPTemplate] = []
let homeItem = CPListItem(text: "Home", detailText: "")
homeItem.handler = { item, completion in
self.interfaceController?.pushTemplate(self.createNowPlaying(), animated: true, completion: nil)
completion()
}
let homeSection = CPListSection(items: [homeItem])
let homeTemplate = CPListTemplate(title: "Home", sections: [homeSection])
homeTemplate.tabImage = UIImage(systemName: "house.fill")
let settingItem = CPListItem(text: "Setting", detailText: "")
let settingSection = CPListSection(items: [settingItem])
let settingTemplate = CPListTemplate(title: "Home", sections: [settingSection])
settingTemplate.tabImage = UIImage(systemName: "gearshape.fill")
tabs.append(homeTemplate)
tabs.append(settingTemplate)
let tabBar = CPTabBarTemplate(templates: tabs)
return tabBar
}
}
Ở đây mình chỉ sử dụng các template mà Audio type hỗ trợ, các bạn cũng có thể sử dụng các template mà Audio không hỗ trợ để trải nghiệm nhé, ví dụ như sử dụng Action Sheet template. (Lưu ý là app sẽ crash nhé!!!)
Ngoài ra các bạn cũng có thể xây dựng ứng dụng của mình với các type còn lại để trải nghiệm nhé!
Kết quả
Sau khi build trên xCode Simulator mình được kết quả như sau:
Trên đây là phần mình chia sẻ về cách tạo một ứng dụng hỗ trợ CP sử dụng type là template được cung cấp bởi Apple. Bài tiếp theo mình sẽ chia sẻ về cách tạo một ứng dụng hỗ tợ CP với type Automaker
Mình hi vọng bài viết có thể giúp ích được cho các bạn. Chúc các bạn thành công!
Hi. Apple CarPlay không còn xa lạ với nhiều người, đặc biệt là các anh em sử dụng xe hàng ngày. Vậy làm sao để một ứng dụng hỗ trợ CP? (CarPlay). Trong bài này mình sẽ giới thiệu đến anh em về CP.
CP là gì?
CP là một cách an toàn để sử dụng iPhone trên xe ô tô, CP sẽ thực hiện các tác vụ mà người dùng muốn thực hiện với iPhone trong khi lái xe.
CP Types
Ở thời điểm hiện tại Apple cung cấp 9 CP types
Audio
Communication (Messaging & calling)
Driving task
EV charging
Fueling
Navigation
Packing
Quick food ordering
Automaker
Đến đây chắc hẳn các bạn cũng thắc mắc tại sao type Automaker mình lại highlight lên như vậy. Thì đây là một type rất đặc biệt. Và ở phần 1 này mình chỉ chia sẻ về 8 types bên trên, riêng type Automaker mình sẽ chia sẻ ở phần tiếp theo.
Mỗi CP type sẽ có một entitlement key, key này chính là để enable/disable tính năng CP trong các ứng dụng
Entitlement
Key
Minimum version
CarPlay Audio App (CarPlay framework) App supports the CarPlay framework. Include both CarPlay audio app entitlements if your app supports the CarPlay framework and the Media Player framework.
com.apple.developer.carplay-audio
iOS 14
CarPlay Audio App (Media Player framework) Deprecated. App supports the Media Player framework. Include both CarPlay audio app entitlements if your app supports the CarPlay framework and the Media Player framework.
com.apple.developer.playable-content
CarPlay Communication App App supports the CarPlay framework, and SiriKit intents for messaging or VoIP calling apps. May be combined with the optional CarPlay Messaging App and CarPlay VoIP Calling App entitlements to support iOS 13 and earlier.
com.apple.developer.carplay-communication
iOS 14
CarPlay Messaging App Deprecated. App relies solely on SiriKit and supports SiriKit intents to send, request, and modify messages. May be combined with the CarPlay Communication App entitlement, and the optional CarPlay VoIP Calling App entitlement to support iOS 13 and earlier.
com.apple.developer.carplay-messaging
CarPlay VoIP Calling App Deprecated. App relies solely on SiriKit and CallKit, and supports SiriKit intents for starting calls and requesting a list of calls. May be combined with the CarPlay Communication App entitlement, and the optional CarPlay Messaging App entitlement to support iOS 13 and earlier.
com.apple.developer.carplay-calling
CarPlay Driving Task App App supports the CarPlay framework.
com.apple.developer.carplay-driving-task
iOS 16
CarPlay EV Charging App App supports the CarPlay framework. May be combined with the CarPlay Fueling App entitlement.
com.apple.developer.carplay-charging
iOS 14
CarPlay Fueling App App supports the CarPlay framework. May be combined with the CarPlay EV Charging App entitlement.
com.apple.developer.carplay-fueling
iOS 16
CarPlay Navigation App App supports the CarPlay framework.
com.apple.developer.carplay-maps
iOS 12
CarPlay Parking App App supports the CarPlay framework.
com.apple.developer.carplay-parking
iOS 14
CarPlay Quick Food Ordering App App supports the CarPlay framework.
com.apple.developer.carplay-quick-ordering
iOS 14
đây là các key của 8 types được cung cấp bưởi Apple
Note: Khi xây dựng một ứng dụng có hỗ trợ CP, thì chúng ta chỉ được chọn một trong 8 type này. Và config với key tương ứng trong file entitlement, như vậy là compiler đã hiểu là ứng dụng này có hỗ trợ CP.
CP Templates
Apple cung cấp 12 templates để hiển thị trên CP. Chúng ta không thể thay đổi layout của của các template này mà chỉ có thể input data vào để hiển thị.
Ở trên mình đã giới thiệu đến các bạn types và templates trong CP. Vậy nó có mối quan hệ gì với nhau không?
Câu trả lời là có, mỗi CP type sẽ hỗ trợ một vài templates.
Ví dụ: với những ứng dụng CP Audio thì chỉ có thể hiển thị được với các templates như Alert, Grid, List, Tab bar, Now Playing
Trong trường hợp chọn một template không hỗ trợ để hiển thị thì app sẽ crash.
Ví dụ: ứng dụng CP Audio không hỗ trợ type Action Sheet, nếu chúng ta sử dụng type Action Sheet để hiển thị thì ứng dụng CP sẽ crash.
Di chuyển màn hình
Như một ứng dụng chạy trên iPhone, thì CP cũng có thể di chuyển màn hình bằng hai phương thức chính là push và present. Nhưng bản chất ở đây là di chuyển giữa các templates Ví dụ: Chúng ta xây dựng ứng dụng CP Audio, màn hình root view là List template, khi bấm vào một item trong list thì di chuyển đến template Now Playing thì đơn giản là chúng ta sử dụng phương thức push hoặc present để di chuyển.
Không phải template nào cũng có thể push và present được. Ví dụ: khi các bạn push đên Grid template thì không vấn đề gì, còn khi các bạn present đến Grid thì CP sẽ crash và báo present không support Grid.
limit khi di chuyển màn hình, hầu hết các app sẽ có độ sâu phần cấp là 5, ứng dụng Fueling sẽ có độ sâu là 3, ứng dụng Driving task và Quick food ordering có độ sâu là 2. Tính từ màn hình root. Ví dụ: khi xây dựng CP Audio các bạn không thể di chuyển quá 5 màn hình Template1 -> Template2 -> Template3 -> Template4 -> Template5 -> Template6 Di chuyển từ Template1 đến Template5 thì không sao, và app sẽ crash khi di chuyển từ Template5 đến Template6
Hướng dẫn khi xây dựng ứng dụng CP
Khi xây dựng một ứng dụng CP thì chúng ta phải tuân thủ theo 8 hướng chung sau đây: (Mình sẽ lấy nguyên các hướng dẫn của Apple cung cấp để cho các bạn tham khảo nhé)
Your CarPlay app must be designed primarily to provide the specified feature to a user (e.g. CarPlay audio apps must be designed primarily to provide audio playback services, CarPlay parking apps must be designed primarily to provide parking services, etc.).
Never instruct users to pick up their iPhone to perform a task. If there is an error condition, such as a required log in, you can let users know about the condition so they can take action when safe. However, user messages must not include wording that asks users to manipulate their iPhone.
All CarPlay user flows must be possible without interacting with iPhone.
All CarPlay user flows must be meaningful to use while driving. Don’t include features in CarPlay that aren’t related to the primary task (e.g. unrelated settings, maintenance features, etc.).
No gaming or social networking.
Never show the content of messages, texts, or emails on the CarPlay screen.
Use templates for their intended purpose, and only populate templates with the specified information types (e.g. a list template must be used to present a list for selection, album artwork in the now playing screen must be used to show an album cover, etc.).
All voice interaction must be handled using SiriKit (with the exception of CarPlay navigation apps, see below).
Ngoài 8 hướng dẫn chung này ra thì một số CP types có các hướng dẫn đặc biệt nữa. Chúng ta có thể tham khảo ở page 6, 7, 8, 9, 10
Môi trường phát triển
Cũng như các ứng dụng trên iPhone khi các bạn muốn chạy trên device thật thì cần certificate và provisioning. Thì ứng dụng CP cũng vậy. Tuy nhiên khi chạy ứng dụng ra simulator thì không cần thiết. Ví dụ: Khi xây dựng một ứng dụng hỗ trợ notification thì cần enable notification ở capabilities, thì với ứng dụng CP cũng cần enable entitlement ở trong Additional Capabilities.
Mục Additional Capabilities của tất cả các Apple Account đều là rỗng, developer phải request đến Apple và đợi họ approve thì mới có thể enable Capabilities để chạy trên device thật.
Account của mình đã được Apple approve với type Audio, mình nhớ là mất khoảng 14 ngày để Apple approve.
Apple cung cấp cho chúng ta hai simulators để thực hiện test trong quá trình phát triển ứng dụng CP
xCode Simulator: đây là simulator tích hợp sẵn trong xCode. Chúng ta có thể mở simulator này lên bằng cách chọn I/O -> External Display -> CarPlay…
CP Simulator: đây là một tool riêng biệt, nó mô phỏng lại môi trường của xe ô tô và phải cài ứng dụng hỗ trợ CP lên iPhone, sau đó kết nối với máy tính và mở CP Simulator lên (sau khi tải tool về thì mở folder Hardware -> CarPlay Simulator), tất cả các apps hỗ trợ CP trên iPhone sẽ hiển thị trên CP simulator. Link tải tool đây nhé, lưu ý các bạn chọn đúng tool mà xCode của mình đang sử dụng nhé
Trên đây là phần giới thiệu của mình về CP, phần tiếp theo mình sẽ chia sẻ việc implement một ứng dụng hỗ trợ CP.
Mình hi vọng bài viết có thể giúp ích được cho các bạn. Chúc các bạn thành công!
Chúng ta chắc là đã quá quen thuộc với ternary conditional operator ( toán tử ba ngôi ) như trên rồi nhỉ. Nhưng với swift 5.9, chúng ta đã có thêm một cách viết khác tường minh hơn đó là sử dụng if / switch. Và trong bài viết này chúng ta sẽ tìm hiểu về nó nhé.
If / switch expression là gì?
Với Swift 5.9. If và switch đã có thể được sử dụng dưới dạng biểu thức. Nói đơn giản thì toán tử ba ngôi được sử dụng như thế nào thì if và switch bây giờ đều có thể sử dụng như vậy.
Ví dụ như bình thường chúng ta đang viết như thế này:
Thì chúng ta hiện nay đã có thể viết như thế này:
Đối với switch có vẻ như là mới mẻ và xịn xò hơn hẳn rồi nhỉ. Nhưng còn if thì sao. Trông cũng không khác gì đối với toán tử ba ngôi mà lại còn phải viết nhiều hơn. Vậy thì nó có gì khác biệt so với toán tử ba ngôi nhỉ.
Đầu tiên: Sử dụng if trông rõ ràng là giúp code được tường minh và dễ theo dõi hơn rồi. Đặc biệt là với những lúc mà có các điều kiện rẽ nhánh lồng nhau thì sự tường minh của if sẽ được thể hiện rõ hơn.
Thứ Hai: Toán tử ba ngôi thì kiểm tra kiểu dữ liệu một cách đồng thời còn if sẽ kiểm tra nó một cách độc lập. Nghe có chút trừu tượng nhỉ. Vậy thì chúng ta sẽ tới với ví dụ nhé:
Ở đây chúng ta có thể thấy. Do toán tử ba ngôi kiểm tra kiểu dữ liệu một cách đồng thời vậy nên 1 ở đây hệ thống sẽ tự hiểu là 1.0. Với If thì không như vậy mà chúng ta cần viết rõ ra hơn.
Lưu ý:
Để sử dụng được if và switch như một biểu thức thì chúng ta cần lưu ý một vài yếu tố sau:
Với mỗi nhánh của if hay switch chỉ được thực thi duy nhất một biểu thức.
Mỗi biểu thức được tạo ra ở các nhánh đều phải cùng một kiểu dữ liệu.
If luôn đi kèm với else
Và bài viết này chúng ta đã được tìm hiểu về If / switch expression ở trên swift 5.9. Vẫn còn rất nhiều thứ mới nữa ở swift 5.9 và chúng ta sẽ tiếp tục tìm hiểu chúng ở các phần tiếp theo nhé. Xin chân trọng cảm ơn!
Hôm nay chúng ta sẽ nâng cấp thêm vũ khí giúp anh em iOS Developer tự tin chiến đấu hơn . Đây là một chủ đề khá nhỏ trong iOS & Swift nói chung, tuy nhiên nó lại có một tầm ảnh hưởng khá là lớn. Nên khi bạn nắm bắt được Raw String, thì có sẽ có thêm một công cụ khá là mạnh trong tay. Let’s goooooo !
Raw String là gì?
Raw String lần đầu được giới thiệu ở Swift 5, cho chúng ta khả năng viết chuỗi tự nhiên hơn, đặc biệt khi sử dụng dấu gạch chéo ngược và dấu ngoặc kép. Trong một số trường hợp, chẳng hạn như biểu thức Regex, chúng ta sẽ thấy được sức mạnh của Raw String.
Swift 5 cung cấp cho chúng ta khả năng khai báo một dấu phân cách chuỗi tùy chỉnh bằng cách sử dụng ký hiệu "#" hay còn được gọi là dấu thăng. Khi bạn sử dụng "#" với một chuỗi, nó sẽ ảnh hưởng đến cách Swift hiểu các ký tự đặc biệt trong chuỗi: “\” không còn hoạt động như một ký tự để thoát chuỗi, vì vậy \n được hiểu là dấu gạch chéo ngược rồi đến chữ “n” thay vì ngắt dòng và \(variable)sẽ được bao gồm dưới dạng các ký tự đó.
Công dụng của Raw String
Đầu tiên hãy đi vào một ví dụ nhỏ
let regularString = "\\Hello \\World"
let rawString = #"\Hello \World"#
Như bạn có thể thấy, ở string thứ 2 sử dụng # để đánh dấu đó là một Raw String, output của hai chuỗi này sẽ như nhau nhưng khi dùng Raw String trông có vẻ sáng sủa hơn nhỉ ?.
Thêm ví dụ nữa cho mọi người thấy công dụng của Raw String:
let swift4 = "This is \"Swift 4.x\"."
print(swift4)
let swift5 = #"This is "Swift 5.x"."#
print(swift5)
Trông có vẻ rõ ràng hơn rồi, khai báo & kết thúc một String với dấu #, ta có thể sử dụng các kí tự đặc biệt như là một kí tự bình thường trong chuỗi, giúp chúng ta không phải sử dụng thêm các dấu \ làm code trông khá là lú ?.
Raw String với Variable
let name = "Techover"
let greeting = #"Hello, \#(name)!"#
print(greeting)
Với String bình thường, ta sẽ sử dụng cú pháp \(variableName) để đưa giá trị biến vào chuỗi. Còn với Raw String ta sẽ phải thêm dấu # vào nữa như ví dụ bên trên.
Raw String với Multi-line
let example = "Hello bro"
let message = #"""
This is rendered as text: \(example).
This uses string interpolation: \#(example).
"""#
print(message)
Cũng khá là easy và tiện lợi nhỉ, không như String xuống dòng linh tinh cái là đi ngay ??
Raw String với dấu #
Khi muốn sử dụng dấu # trong một Raw String sẽ khác một chút đó
let str = #"My dog said "woof"#gooddog"#
Xcode sẽ ngăn cản bạn thực hiện đoạn code trên. Vì nó sẽ xác định dấu # tiếp theo là kết thúc chuỗi Raw String rồi. Do đó, phần còn lại sẽ trở thành lỗi. Chế cháo đi một tí mới hết lỗi nè
let str = ##"My dog said "woof"#gooddog"##
print(str)
Như trên, output của chúng ta sẽ có đầy đủ các dấu " & # luôn. Như vậy, khi ta khai báo bao nhiêu dấu # ở đầu, thì sẽ phải có bấy nhiêu dấu # ở cuối của Raw String. Lúc này, Raw String của ta mới có ý nghĩa.
let zero = "This is a string"
let one = #"This is a string"#
let two = ##"This is a string"##
let three = ###"This is a string"###
let four = ####"This is a string"####
Lan man một hồi giờ tổng kết lại nè
Raw String hữu ích vì một lý do: Đơn giản hóa String, giúp chúng ta dễ đọc dễ tiếp cận và dễ dàng sửa chữa
Đặc biệt trong các biểu thức Regex, khi mà chúng ta phải sử dụng rất nhiều kí tự đặc biệt, một ví dụ về một biểu thức Regex khá là nhiều dấu \
let regex = try NSRegularExpression(pattern: "\\\\\\([^)]+\\)")
Tuy nhiên với Raw String, chúng ta có thể bớt đi một nửa số dấu \ chúng ta sử dụng. Đơn giản biểu thức của chúng ta sẽ còn lại là:
let regex = try NSRegularExpression(pattern: #"\\\([^)]+\)"#)
Lời kết
Như vậy là sau một hồi bàn luận về Raw String, hi vọng các bạn có thể áp dụng được vào code của mình để code của chúng ta ngày càng xịn sò hơn. Cảm ơn các bạn vì đã đọc bài viết này. Hẹn gặp lại các bạn ở các post tiếp theo ?
Ở phần trước mình đã hướng dẫn các bạn các cách để fake GPS location trên Simulator của iPhone. Nếu các bạn muốn tìm hiểu thêm thông tin thì có thể tham khảo ở đường link: HƯỚNG DẪN CÁCH FAKE GPS TRÊN SIMULATOR
Trong bài này mình sẽ hướng dẫn các bạn Fake GPS location on Xcode nhằm mục đích giúp các bạn có thêm các cách để giảm thời gian và dễ dàng test các ứng dụng liên quan tới GPS, location services. Đặc biệt hữu dụng với các ứng dụng yêu cầu người dùng phải di chuyển kiểu như app chạy bộ, đạp xe, chỉ đường, hướng dẫn … v.v.
Giải thích về ý tưởng
Để dễ dàng cho việc test các tính năng yêu cầu người dùng ứng dụng phải di chuyển, chúng ta sẽ sử dụng cách Fake GPS location bằng cách sử dụng GPX file trên Xcode. GPX file cho phép chúng ta thêm các vị trí và thời gian di chuyển đến vị trí đó, từ đó ta có thể tạo ra một danh sách các điểm cần di chuyển đến để thực hiện test ứng dụng mà không cần di chuyển thực tế. GPX file cho phép ta có thể tạo ra các kịch bản test di chuyển một cách dễ dàng và tiết kiệm thời gian và công sức. Ngoài ra ta có thể sử dụng lại được nhiều lần và dễ dàng chỉnh sửa theo các kịch bản test.
Từ các tính năng như trên chúng ta có thể tạo ra một ứng dụng chuyên để Fake GPS Location từ đó giả lập vị trí của iPhone.
NOTE
Đây là fake GPS location của thiết bị luôn, và nó hoạt động và ảnh hưởng lên tất cả các ứng dụng đang sử dụng Map, Location Services. Vậy nên các bạn lưu ý khi sử dụng nha.
Hướng dẫn Fake Location GPS trên XCode sử dụng GPX file
Để tiện cho việc demo các bạn có thể tải xuống source ở link dưới đây:
Bước 1: Tạo file GPX để fake GPS Location trên Xcode
Sử dụng Xcode mở project DemoGPXMapKit lên -> Bấm chuột phải vào tạo new file…
Khi của sổ mở lên, ở ô tìm kiếm bạn điền từ khoá “GPX” thì sẽ được kết quả như hình dưới đây
Bấm Next và đặt tên cho file, ở ví dụ này mình sẽ đặt là mydinh-hanoi. Đặt tên xong Xcode sẽ tạo cho các bạn một file và có sẵn nội dung là một điểm.
Các bạn có thể thay đổi file GPX tuỳ theo trường hợp mà bạn muốn. Ở đây mình muốn Fake GPS Location về Sân vận động Mỹ Đình nên mình sửa lại file như sau:
Về toạ độ lat, lon các bạn có thể sử dụng Google Map để lấy -> bấm chuột phải vào vị trí bạn muốn lấy vị trí sẽ hiển thị như hình và bạn chọn vào hàng có toạ độ là nó tự copy toạ độ cho các bạn, rồi các bạn paste vào file GPX để thay đổi vị trí một cách dễ dàng.
Bước2: Chỉnh sửa scheme để file GPX fake GPS Location tự động ăn khi chạy ứng dụng
Chọn Scheme -> Edit Scheme như hình dưới
Một popup hiển thị lên, lúc này bạn chọn Run -> Options. – Ở mục CoreLocation tích vào Allow Location Simolation. – Ở mục Default Location chọn file gpx của các bạn, trường hợp này của mình là mydinh-hanoi. Nếu không chọn thì mặc định nó sẽ là None và khi đó nó sẽ ăn vào location của Simulator
Thực hiện Build(Command + R) ứng dụng để ứng dụng sử dụng file GPX.
Khi này ở thanh Debug chúng ta sẽ có thêm icon Location để cho phép chúng ta thay đổi vị trí Fake GPS location một cách dễ dàng và nhanh chóng hơn.
Kết quả thu được như sau:
Các bạn có thể tạo ra nhiều file GPX với nhiều vị trí khác nhau để thuận tiện cho việc test, hoặc có thể sửa trực tiếp file GPX rồi chọn lại mà không cần build lại ứng dụng.
Fake GPS Location di chuyển theo đường đi bằng file GPX
Chúng ta sẽ tạo mới một file như các bước mình đã hướng dẫn ở đầu bài. Nội dung thì sửa lại như sau:
Ở đây mình có thêm vào 3 waypoints để fake GPS location, nhằm giả lập việc di chuyển qua các điểm này. Các bạn để ý kỹ thì mình có thay đổi thời gian của các waypoint tăng dần và cách nhau 10s. Các bạn có thể tính toán vận tốc và quãng đường để thực hiện giả lập một cách chân thực nhất, ví dụ như tốc độ của ô tô với máy bay thì sẽ khác nhau vì vậy cùng quãng đường thời gian cũng sẽ khác nhau.
Giờ khi các bạn chọn icon location sẽ hiển thị ra file bạn mới tạo và có thể thay đổi luôn mà không cần phải build lại nữa, như mình mới tạo file ride-mydinh-hanoi
Kết quả chúng ta sẽ thu được như sau
Tuy nhiên ta có thể thấy nó cứ lặp đi lặp lại vô hạn mà không dừng lại tại điểm cuối cùng. Để cho nó dừng lại ở điểm cuối cùng thì chúng ta sẽ sử dụng thêm một waypoint nữa và thay đổi vị trí không đáng kể và tăng thời gian di của điểm này cách xa so với điểm gần cuối như sau:
You want to check your UT index? You want to display the coverage index on xcode to know if your code has reached the standard? How to show Coverage index on xcode? How to enable UT Coverage on XCode? Those are the questions I get asked often, but there aren’t many tutorials on the internet yet. So today I will guide you to enable Code Coverage on Xcode
How to enable UT Coverage on Xcode 13.4.1 or below?
For projects using Xcode 13 or below to create, we do the following:
Step 1: Select Scheme -> edit Scheme -> a popup is displayed
Step 2: In the left menu of the popup select Test, then in the upper menu of the popup select option -> tick Code Coverage for
Step 3: Run test app (command + U)
How to enable UT Coverage on Xcode 14.0 or later?
For projects using Xcode 14 or later to create, we do the following:
Step 1: Select Scheme -> edit Scheme -> a popup is displayed
Step 2: In the left menu of Popup select Test, then hover on Test Plan as shown and then click the button to go to settings.
Step 3: Change code coverage to On
If you don’t need to test UI, you can remove the test plan for UI to make Unit tests run faster
Step 4: Run test (command + U), ta thu được kết quả như sau
Ở SCD1 các dữ liệu mới sẽ ghi đè dữ liệu cũ, không theo dõi dữ liệu lịch sử.
Ví dụ:
Original Record – Dữ liệu gốc
Cust_ID
Name
City
1001
Nguyễn Văn A
HCM
1002
Nguyễn Văn B
Nam Định
Updated Record – Dữ liệu được thay đổi
Cust_ID
Name
City
1001
Nguyễn Văn A
Hà Nội
1002
Nguyễn Văn B
Nam Định
Ưu điểm: Dễ bảo trì.
Nhược điểm: Không kiểm tra được dữ liệu lịch sử.
2. SCD1 validation test cases
Kiểm tra SCD Loại 1 khá đơn giản vì chúng ta có thể đạt được kết quả bằng cách so sánh đơn giản giữa dữ liệu nguồn và dữ liệu đích. Ví dụ chúng ta có bẳng nguồn và bảng đích như sau:
Employee table – bảng nguồn với các cột:
Cust_ID
Name
City
EMPLOYEE_DIM SCD Type 1 – bảng đích với các cột dưới đây:
Cust_ID
Name
City
Partition_date
2.1 Test case 1: Chúng ta sẽ đi kiểm tra số lượng cột, tên cột và data type từng cột có đúng với yêu cầu document không?
VD: Cus_ID có type là bigint, thì trên bảng đích data type cũng là bigint.
Target Query: Describe Table_Name;
or Desc Table_Name
2.2 Test case 2: Kiểm tra số lượng records.
Source Query: Select count (*) from db.Emlpoyee
Target Query: Select count (*) from db.Employee_Dim
2.3 Test case 3: Kiểm tra logic insert
Insert thêm records mới ở bảng nguồn:
Chúng ta sẽ thêm các records mới tại bảng nguồn, rồi khởi chạy job ETL. Sau khi job chạy thành công thì kiểm tra dữ liệu ở bảng đích có lên đúng và đủ so với bảng nguồn không.
Delete records ở bảng nguồn
Ngược lại với thêm mới, chúng ta sẽ xóa bớt dữ liệu ở bảng nguồn rồi chạy job ETL. Sau khi job chạy thành công thì kiểm tra dữ liệu ở bảng đích và bảng nguồn có mapping với nhau không.
2.4 Test case 4: Kiểm tra logic update
Tại bảng nguồn chúng ta sẽ update các bản ghi trước đó, rồi chạy job ETL. Sau khi job chạy thành công, kiểm tra dữ liệu bảng đích có lên đúng so với bảng nguồn không.
2.5 Test case 5: Kiểm tra dữ liệu có bị duplicate không? – Xác minh tính duy nhất của dữ liệu
Target Query:
Select Cust_ID, Name, City, Partition_date, count(*) from db.Employee_Dim group by Cust_ID, Name, City, Partition_date having count(*) > 1 ;
Select Cust_ID, count(Cust_ID) from db.Employee_Dim group by Cust_ID having count(Cust_ID) > 1;
2.6 Test case 6: Kiểm tra dữ liệu null
Target Query:
Select * from db.Employee_Dim where Cust_ID is not null;
Kết luận
SCD1: các dữ liệu mới sẽ ghi đè dữ liệu cũ, không theo dõi dữ liệu lịch sử
Kiểm tra số lượng bản ghi bảng đích so với bảng nguồn
Sau khi thay đổi dữ liệu bảng nguồn (insert, delete, update) phải thực hiện quy trình ETL để EMPLOYEE_DIM có dữ liệu mới nhất
Sửa đổi một vài bản ghi trong bảng nguồn bằng cách cập nhật các giá trị trong các cột chính (key columns) để kiểm tra logic update
Xác minh tính duy nhất của dữ liệu
Xác minh rằng sự khác biệt là như mong đợi
Trên đây là những chia sẻ của mình về testing SCD type 1 trong ETL testing, mong rằng bài viết này sẽ giúp ích được cho các bạn. Nếu mọi người có thắc mắc hay câu hỏi gì đừng ngần ngại comment và cùng nhau giải đáp nhé!
Hi, trong quá trình phát triển các ứng dụng iOS, đôi khi chúng ta sẽ được phát triển các tính năng liên quan tới bản đồ, một số ứng dụng còn cần phải sử dụng Location Service để hiển thị vị trí của người dùng. Vì vậy khi phát triển ứng dụng bạn sẽ cần phải kiểm tra ứng dụng của mình xem nó chạy đúng chưa, hiển thị đúng vị trí trên bản đồ chưa? Nếu chúng ta cầm thiết bị chạy đi chạy lại thì thật quá tốn công, tốn sức. Thấu hiểu nỗi khổ của các iOS developers Apple đã phát triển tính năng Fake GPS trên Simulator giúp cho việc kiểm tra ứng dụng của mình một cách dễ dàng và đỡ mất công mất sức hơn.
Fake GPS trên Simulator – Di chuyển đến trụ sở chính của Apple
Để bật tính năng này chúng ta mở Simulator lên, trên Menu bar của Simulator chọn Features -> Location -> Apple như hình dưới đây
Kết quả chúng ta sẽ được vị trí GPS ở trụ sở của Apple.
Fake GPS trên Simulator – Di chuyển đến vị trí bất kì trên bản đồ
Việc fake GPS trên Simulator đến vị trí trung tâm Apple không giúp ích nhiều cho việc kiểm tra ứng dụng của bạn, vì vậy mình sẽ hướng dẫn các bạn cách để Fake GPS trên Simulator đến vị trí bất kì trên bản đồ. Để làm được điều này chúng ta cần Kinh độ và Vĩ độ của điểm chúng ta cần fake GPS. Các bạn có thể lên Google Map để lấy toạ độ nhá. Ví dụ mình sẽ lấy toạ độ của Đền Ngọc Sơn trên Hồ Hoàn Kiếm ở Hà Nội.
Để ý hình mình có khoanh, Ta sẽ lấy toạ độ (lat, long) theo thứ tự từ trái qua phải là Latitude và Longitude ở trên URL của google map. Trong ví dụ này Latitude: 21.0298318 và Longitude: 105.8532851.
Khi lấy được toạ độ cần fake GPS trên Simulator rồi thì ta sẽ làm như sau: Trên Menu bar của Simulator -> chọn Features -> Location -> Custom Location… -> Điền Latitude và Longitude vào và bấm OK như hình dưới.
Vậy là chúng ta đã có thể fake GPS đên mọi nơi mà chúng ta cần để kiểm tra ứng dụng của mình.
NOTE: Có một lưu ý là khi các bạn copy Latitude và Longitude từ Google đôi khi ngôn ngữ không giống với simulator nên simulator nó không nhận, bạn hãy để ý và thay dấu chấm “.” <-> thành dấu phẩy “,” hoặc ngược lại nhé.
Fake GPS trên Simulator – Fake trường hợp vị trí chuyển động liên tục.
Trong thực tế có một số ứng dụng yêu cầu ta phải hiển thị vị trí của người dùng chính xác và liên tục, tuy nhiên để kiểm tra trường hợp này một cách mượt mà thì sử dụng các cách phía trên là bất khả thi và tốn rất nhiều thời gian, vì vậy apple đã cung cấp một số cách để thuận tiện cho việc kiểm tra vị trí di chuyển đó là: City Run, City Bicycle Ride và Freeway Drive. Trên Menu bar của Simulator -> chọn Features -> Location -> City Run hoặc City Bicycle Ride hoặc Freeway Drive.
Vậy là bạn đã có thể ngồi 1 chỗ và test được việc di chuyển trên ứng dụng của mình mà không tốn một giọt mồ hôi nào.
Hiện tại Apple chỉ hỗ trợ 3 loại di chuyển như trên vì vậy nó khá hạn chế trong việc kiểm thử, trong trường hợp các bạn cần linh hoạt hơn thì chúng ta có thể sử dụng file GPX để fake GPS trên Simulator chủ động hơn, tuy nhiên cách này sẽ phức tạp hơn một chút. Vì vậy mình sẽ hướng dẫn các bạn ở bài viết tiếp theo nhé!