Như các bạn đã biết hiện nay môi trường thực thi sử dụng trong Lambda phần lớn đang sử dụng Node hay Python. Tuy nhiên trên thực tế đôi khi bạn cần sử dụng một môi trường thực thi khác như Java chẳng hạn. Trên thực tế thì AWS cũng đang hỗ trợ khá nhiều môi trường thực thi khác nhau. Có nhiều lý do dẫn tới việc chúng ta phải sử dụng một môi trường thực thi nào đó tuỳ vào tình hình dự án. Trong bài viết này tôi sẽ hướng dẫn các bạn xây dựng ứng dụng Lamba sử dụng môi trường thực thi là Java.
Chúng ta cần Docker bởi vì công cụ thực thi SAM CLI sẽ sử dụng docker container để thực thi ứng dụng. Bạn thao khảo đường dẫn sau để cài đặt Docker
SAM
Chúng ta sẽ sử dụng SAM vì chúng ta cần một môi trường thực thi có thể chạy trên môi trường cục bộ và có thể debug được. Để cài SAM bạn làm theo hướng dẫn sau:
brew tap aws/tap
brew install aws-sam-cli
Chúng ta sử dụng brew để cài SAM nên bạn cần cài brew trước. Nếu chưa cài brew thì bạn có thể thao khảo cách cài brew như sau:
Chúng ta sẽ sử dụng môi trường thực thi Java nên việc cài đặt Oracle JDK là đương nhiên đúng không. Các bạn tham khảo cách cài đặt Oracle JDK tại đây nhé.
Maven
SAM sẽ sử dụng maven để build nên chúng ta cần cài đặt thêm maven. Để cài đặt Maven các bạn sử dụng lệnh sau:
brew install --ignore-dependencies maven
Các bạn chú ý, chúng ta cần sử dụng --ignore-dependencies để bỏ qua việc cài đặt Open JDK nhé. Mặc định maven sẽ sử dụng Open JDK. Tuy nhiên chúng ta đã cài đặt Oracle JDK rồi nên không cần cài Open JDK nữa.
hieunv@HieuNV hieunv % sam init -r java11
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
Which dependency manager would you like to use?
1 - maven
2 - gradle
Dependency manager: 1
Project name [sam-app]:
Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git
AWS quick start application templates:
1 - Hello World Example: Maven
2 - EventBridge Hello World: Maven
3 - EventBridge App from scratch (100+ Event Schemas): Maven
Template selection: 1
-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: java11
Dependency Manager: maven
Application Template: hello-world
Output Directory: .
Next steps can be found in the README file at ./sam-app/README.md
Trước khi thực thi bạn cần build project trước
hieunv@HieuNV hieunv % cd sam-app
hieunv@HieuNV sam-app % sam build
Building resource 'HelloWorldFunction'
/usr/local/bin/mvn is using a JVM with major version 13 which is newer than 11 that is supported by AWS Lambda. The compiled function code may not run in AWS Lambda unless the project has been configured to be compatible with Java 11 using 'maven.compiler.target' in Maven.
Running JavaMavenWorkflow:CopySource
Running JavaMavenWorkflow:MavenBuild
Running JavaMavenWorkflow:MavenCopyDependency
Running JavaMavenWorkflow:MavenCopyArtifacts
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
Khởi động ứng dụng (trước khi khởi động bạn cần đảm bảo rằng Docker đang hoạt động)
hieunv@HieuNV sam-app % sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-03-22 22:07:45 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
Chúng ta thử truy cập vào http://127.0.0.1:3000/hello bằng Postman. Nếu các bạn chưa chạy lần nào thì sẽ phải chờ hơi lâu một chút để Docker tải image cần thiết.
Trong bài viết này tôi đã hướng dẫn các bạn cách viết một API bằng Lambda sử dụng môi trường thực thi Java. Hy vọng bài viết sẽ giúp ích cho dự án của các bạn.
Trong Swift, chúng ta có khá nhiều cách để truyền dữ liệu qua lại giữa các đối tượng. Bài viết này mình muốn chia sẻ với các bạn về một số kỹ thuật phổ biến và ưu nhược điểm của nó. Bài viết này mình sẽ đề cập đến 3 cách phổ biến đó là Delegation, Closure và NotificationCenter Observation
Bài toán
Màn hình của mình cần làm có một UITableView, trong UITableView này chứa các UITableViewCell các cell thì có chứa 2 UIButton Dark và Light. Việc của mình phải làm là mỗi khi người dùng tương tác với button ở trong cell thì UIViewController sẽ bắt được sự kiện và hiển thị lên màn hình thông tin cell và hành động mà người dùng vừa tương tác.
Các bạn tải về project bắt đầu này để tiện hơn trong quá trình thực hành nhé:
Delegation là một design pattern cho phép đối tượng gửi thông điệp(data, message …) đến đối tượng khác khi có một sự kiện xảy ra. Ví dụ ta có 2 đối tượng A và B, trên B thực hiện hành động gửi thông điệp sang A để A thực hiện hành động dựa trên kết quả hành động trên B.
Do chúng bài toán của chúng ta cần bắt hành động của người dùng khi họ action lên các button trên cell vì thế trong trường hợp này trong UITableViewCell chúng ta cần tạo protocol cho MyTableViewCell.swift cụ thể như sau:
Ở đây mình tạo ra protocol định nghĩa các action trên cell. Khi người dùng bấm vào button Dark nó sẽ call protocol này tương tự với Button Light.
Tiếp đến chúng ta tạo thêm 2 variables để lưu delegate và indexPath:
var indexPath: IndexPath?
weak var delegate: ActionOnCell?
indexPath để lưu lại cell mà ngươi dùng tương tác.
delegate để biết đối tượng nào đang conform protocol của MyTableViewCell
Đối với delegate chúng ta cần khai báo weak để tránh tham chiếu strong dẫn đến Retain cycle, không giải phóng được các object này vì nó đang tham chiếu tới nhau.
Tiếp đến chúng ta cần gọi các protocol tương ứng khi người dùng tương tác lên các button trên cell:
@IBAction func dark(_ sender: Any) {
if let delegate = delegate {
delegate.didTapDark(indexPath: indexPath)
}
}
@IBAction func light(_ sender: Any) {
if let delegate = delegate {
delegate.didTapLight(indexPath: indexPath)
}
}
Vậy là chúng ta đã setup protocol cho MyTableViewCell.swift giờ tất cả những UIViewController nào sử dụng cell này đều có thể conform protocol của nó để bắt được event khi người dùng tương tác lên các button cell.
Giờ chúng ta quay lại file ViewController.swift kéo xuống hàm cellForRowAt indexPath của tableview và update như sau:
Chúng ta gán lại giá trị indexPath cho các cell. Và set delegate cho Cell là self(viewController hiện tại) Lúc này XCode sẽ báo lỗi Cannot assign value of type ‘ViewController’ to type ‘ActionOnCell?’ vì chúng ta chưa conform protocol ActionOnCell trên ViewController.
Vì vậy chúng ta sẽ tạo 1 extension của ViewController và conform ActionOnCell
Khi người dùng tap vào button trên cell nó sẽ call protocol tương ứng và trả dữ liệu về cho viewController vì vậy bạn có thể sử dụng dữ liệu mà bạn muốn để update dữ liệu lên màn hình.
Các bạn Build project sẽ nhận được kết quả như sau:
NotificationCenter observation
Là một cơ chế gửi thông báo cho phép truyền phát thông tin đến các đối tượng đã đăng ký quan sát notification đó.
Chúng ta sẽ dựa trên 2 cơ chế post và observer của NotificationCenter để gửi và nhận dữ liệu giữa các đối tượng. Đối với notification thì chúng ta có thể sử dụng gửi thông tin từ một đối tượng đến nhiều đối tượng khác đã đăng ký theo dõi notification đó.
Cụ thể trong bài toán này chúng ta sẽ làm như sau: Tạo 2 notification Name đinh nghĩa việc người dùng bấm vào Button Dark và Light:
extension Notification.Name {
static let didTapDarkNotification = NSNotification.Name(rawValue: "didTapDarkNotification")
static let didTapLightNotification = NSNotification.Name(rawValue: "didTapLightNotification")
}
Mở file MyTableViewCell.swift thực hiện việc phát(post) thông báo tại 2 event của 2 button trên cell cụ thể như dưới đây:
Nhiệm vụ của 2 hàm này là để khi nào người dùng bấm vào nut Dark hoặc Light thì NotificationCenter sẽ gửi đi một notification, những đối tượng nào đang lắng nghe các notification name đó sẽ nhận được thông điệp.
Vì vậy chúng ta cần add observer cho ViewController.swift để nó nhận được thông tin khi người dùng tương tác lên các button trên cell. Chúng ta sẽ làm như sau:
Chúng ta cần đăng ký theo dõi notification ở viewWillApper và Remove theo dõi notification khi viewWillDisappear vì nếu chúng ta không remove view controller sẽ luôn nhận được thông báo khi mà nó còn trong view hierarchy dẫn đến những lỗi không mong muốn.
Ý tưởng ở đây chúng ta sẽ tạo 1 closure callback có 2 tham số là action type và dữ liệu truyền lại là index path.
Mở file MyTableViewCell.swift và thêm 1 enum định nghĩa các kiểu action trên cell
enum ActionType {
case dark
case light
}
Tạo closure cho MyTableViewCell
var didTapButton: ((ActionType, IndexPath?) -> Void)?
Gọi closure khi người dùng bấm vào các nút trên cell
@IBAction func dark(_ sender: Any) {
if let didTapButton = didTapButton {
didTapButton(.dark, indexPath)
}
}
@IBAction func light(_ sender: Any) {
if let didTapButton = didTapButton {
didTapButton(.light, indexPath)
}
}
Tiếp đến để nhận được event khi người dùng bấm vào các button chúng ta cần gán giá trị cho closure ở nơi mà bạn muốn. Cụ thể trong trường hợp này là ViewController.swift
Giờ run ứng dụng chúng ta sẽ được kết quả như 2 cách trên.
Đánh giá
Delegation: là cách dùng rất phổ biến và đễ sử dụng nhât khi truyền dữ liệu giữa các đối tượng. Nó dựa vào các protocol để truyền dữ liệu qua lại giữa các đối tượng. Thường dùng trong các trường hợp truyền dữ liệu dạng 1 – 1. Tuy nhiên nếu bạn muốn sử dụng delegate dạng 1 – n hãy tham khảo bài viết này https://magz.techover.io/2019/08/09/swift-design-patterns-multicast-delegate/
NotificationCenter: Là dạng truyền nhận dữ liệu 1 – n hoặc 1 – n. Và khi một thông báo được đẩy đi tất cả những đối tượng đã đăng ký nhận thông báo đó sẽ nhận được thông báo. Khi bạn dùng cần phải kiểm soát chặt các notification. Trong mỗi trường hợp khác nhau chúng ta lại có cách đăng ký notification và remove nó ở các chỗ khác nhau. VD: – Đối với các trường hợp bình thường chúng ta sẽ phải thêm notification ở ViewWillAppear và remove nó ở viewWillDisappear để đảm bảo lần viewWillAppear tiếp theo nó không đăng ký lại dẫn đến bị lặp nhiều lần. – Chúng ta không thể để ở viewDidLoad vì nếu remove ở ViewWillDisappear thì khi pop lại sẽ mất notification, nếu không remove thì khi nó vẫn còn trong view hierarchy chưa bị giải phóng nó sẽ vẫn nhận được notification mặc dù chungs ta không mong muốn điều đó. Trong tất cả thì cách này là cách rắc rối nhất. Bạn chỉ nên dùng khi muốn thực hiện dạng truyền dữ liệu 1-n
Closure: Là cách dùng khá phổ biến hiện tại, vì nó là cách viết khá gọn gàng vì vậy tiết kiệm được thời gian code. Tuy nhiên cách viết của nó khá khó hiểu với người mới. Các bạn cũng có thể nhận thấy sự phổ biến của nó thông qua các hàm completion, callback mà Apple đã sử dụng rất nhiều trong các API của họ.
Tổng kết
Mình hi vọng bài viết giúp cho các bạn có thể lựa chọn các cách truyền dữ liệu phù hợp với bài toán của mình. Chúc các bạn thành công!
Nếu bài viết có vấn đề gì các bạn hãy comment xuống dưới để mình update nhé!
Mình đã viết khá nhiều bài sử dụng Serverless, tại sao mình lại viết bài này. Thực ra mình cũng mới bắt đầu làm AWS Lambda được một thời gian ngắn. Dự án đầu tiên mình làm Lambda thì đã các bạn đi được đã chọn Serverless để phát triển. Dự án thứ hai mình làm với AWS Lambda thì khách hàng đưa cho mình bộ mã nguồn đã được cấu hình sử dụng Serverless. Mọi thứ đều có vẻ ổn cho đến một ngày mình quyết định thử debug Lambda bằng Visual Studio Code. Mọi thứ trở nên phức tạp và mình tìm thấy SAM, dường như nó đã giải quyết vấn đề của mình nên mình quyết định viết bài này để cho các bạn nếu mới đến với thế giới AWS thì có thể dễ dàng lựa chọn thứ mình cần.
Dự án đầu tiên mình dùng Serverless và viết bằng JavaScript, mọi thứ đều ổn vì mình chỉ dùng Serverless có kết hợp với Serverless Offline để chạy các hàm Lambda API trên máy tính cá nhân được. Việc debug cũng không gặp trở ngại gì do Serverless Offline có hỗ trợ debug. Thế nhưng đến dự án tiếp theo, ngôn ngữ được chọn làm môi trường thực thi là Python và mình thực sự gặp khó khăn. Mình vẫn có thể chạy được các hàm Lambda trên máy tính cá nhân nhưng không thể debug đươc. Và thế là mình bắt đầu tìm hiểu để giải quyết vấn đề này. Rồi mình tìm thấy SAM và mọi thứ dường như được giải quyết.
Ngôn ngữ nào được hỗ trợ?
Serverless Offline hỗ trợ những ngôn ngữ sau:
Python
Ruby
Node
SAM hỗ trợ nhưng ngôn ngữ sau:
Python
Ruby
Node
Java
.NET Core
…
Được hỗ trợ như thế nào?
Serverless Offline là plugin được cá nhân phát triển. Nó không phải gói được hỗ trợ chính thức từ AWS.
SAM được hỗ trợ chính thức từ AWS.
Hỗ trợ debug như thế nào?
Serverless Offline chỉ hỗ trợ debug với Node.
SAM thì có vẻ như đã hỗ trợ tất cả các trình thực thi ở trên. Mình đã thử debug với Java thì thấy vẫn OK.
Môi trường thực thi
Serverless chạy trực triếp trên máy host.
SAM thì sử dụng container trong docker để thực thi.
Các bạn có thể tham khảo hướng dẫn sử dụng Serverless ở các tài liệu sau nhé:
SAM dường như có những lợi thế hơn hẳn so với Serverless. Nếu bạn quyết định phát triển bằng Node thì bạn sẽ không gặp nhiều khó khăn khi dùng Serverless hay SAM. Nếu bạn chọn một môi trường thực thi khác như Python hay Ruby hay bất kỳ môi trường nào khác thì lựa chọn SAM sẽ là quyết định sáng suốt hơn đấy. Mình sẽ hướng dẫn các bạn sử dụng SAM trong loạt bài viết về SAM sau nhé.
Trong lập trình, để có thể tự kiểm tra app để hoạt động chính xác hay chưa, thì ta phải test hết toàn bộ các case xảy ra. Tuy nhiên, nếu làm bằng 1 cách test thủ công thì rất tốn thời gian.
Để có thể test tự động, thì có thể dùng Unit test. Vậy ở bài viết này, mình sẽ giới thiệu về cách sử dụng Unit test trong lập trình iOS.
Nội dung bài viết
Unit test là gì?
Giới thiệu về unit test trong iOS
Useful Test
Khởi tạo Test Target
Run the test
Functional test Demo
Unit test là gì?
Là phương pháp dùng để kiểm tra tính đúng đắn của một đơn vị source code. Một Unit (đơn vị) source code là phần nhỏ nhất có thể test được của chương trình, thường là một phương thức trong một lớp hoặc một tập hợp các phương thức thực hiện một mục đích thiết yếu.
Bạn viết các test case để Xcode tiến hành test các test case đó.
Giới thiệu về Unit test trong iOS
Xcode cung cấp 3 kiểu test chính:
Functional test: tập trung vào test các func.
Performance tests: tập trung vào đo lương thời gian app của bạn thực thi xong các task trên các loại thiết bị khác nhau.
User Interface tests (UI Tests): tập trung vào những tác vụ của người dùng trên UI.
Note:
Functional test & performance test: Là những đoạn test mà bạn tự viết để test sự hoạt động của các func trong app.
UI Test: Ghi lại những thứ mà bạn tương tác trên UI của app.
Useful Test
1 test case được coi là useful khi:
Test case phải có khả năng fail: Nếu test đó không thể fail, thì việc test sẽ rất vô giá trị, bạn nên xốa nó đi.
Test case phải có khả năng success: Nếu test đó không thể success, thì việc test sẽ rất vô giá trị, tương tự ở trên, bạn nên xốa nó đi.
Test case phải được refactor và được viết đơn giản
Khởi tạo 1 Test Target
Để viết được test, trước hết cần tạo 1 Unit test target để viết test:
Điền tên cho class rồi chọn Next.
Xcode imports sẵn cho bạn frameworks XCTest và class được tạo là subclass của XCTestCase.
func setUp(): dùng để thiết lập lại trạng thái trước mỗi lần test.
func tearDown(): dùng để thực hiện dọn dẹp sau khi mỗi lần test kết thúc.
measure: dùng để đo thời gian thực hiện xong việc test -> giúp test performance.
Trình tự mỗi khi thực hiện test 1 test case như sau:
Run the Tests:
Có 3 cách để run test:
Product ▸ Test or Command-U: Cách này sẽ run tất cả test classes trong project.
Click vào button mũi tên ở Test navigator.
Click chọn nút hình kim cương để run 1 test case cụ thể.
Basic Functional Test Demo
Ở ví dụ này, mình sẽ tiến hành việc test xem dữ liệu học sinh ở file json đã chính xác chưa.
Tạo 1 class Person:
class Person: Decodable {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
Tạo 1 class Service chứa các logic thực hiện việc lấy dữ liệu:
class Service {
func getListStudent() -> [Person] {
var students: [Person] = []
guard let url = Bundle.main.url(forResource: "config", withExtension: ".json") else {
return students
}
do {
let data = try Data(contentsOf: url)
let results = try JSONDecoder().decode([Person].self, from: data)
students += results
} catch {
print("Can get data, error: \(error)")
}
return students
}
}
Tiến hành việc viết test thông tin cho sinh viên đầu tiên:
@tesable import + tên project: Cho phép unit tests truy cập đến toàn bộ các dữ liệu kiểu internal của project.
Khai báo 1 biến kiểu service.
Khởi tạo sut mỗi lần bắt đầu thực hiện test 1 test case.
Set sut = nil mỗi khi kết thúc việc test 1 test case.
Viết func test để test thông tin học sinh 1.
Viết các hàm để test.
Note: Khi viết func để test thì phải tên func phải luôn bắt đầu với từ test để Xcode có thể biết đó là 1 test.
Thực hiện tiến hành test func, nhận được kết quả dữ liệu cần kiểm tra đã chính xác:
Để đảm bảo đây là 1 Userful test, thực hiện sửa đổi name của sinh viên 1 trong file json thành "Cuong1" và tiến hành test lại func, nhận được kết quả sau:
Việc test thất bại, đồng thời XCode cũng thông báo ra kết quả để biết sai ở đâu.
Ở phần tiếp theo, mình sẽ nói về performance test, UI Test và 1 vài thứ hay ho mà Xcode support cho việc test.
Ở bài viết trước mình đã hướng dẫn cho các bạn cách upload ứng dụng lên store. Nhưng ứng dụng nào trước khi đẩy lên store chúng ta cũng phải có giai đoạn kiểm thử. Điều đó đảm bảo ứng dụng của bạn phát sinh ít lỗi trong quá trình người dùng sử dụng cũng như đảm bảo ứng dụng chạy đúng theo yêu cầu. Vì vậy hôm nay mình sẽ chia sẻ với các bạn tất tần tật về Testflight ứng dụng được Apple phát hành với nhiệm vụ giúp tester dễ dàng tiếp cận bản build hơn.
Testflight là gì?
Testflight là một ứng dụng được Apple cung cấp để cho Developer của họ upload ứng dụng lên nhằm mục đích kiểm thử ứng dụng. Ứng dụng này gồm 2 phần: Tính năng quản lí cho developer nằm trong App store connect và ứng dụng Testflight là ứng dụng cho tester.
Internal tester: Đây là những App store connect user được phân quyền Admin, App manager, legal, developer … có thể quyền truy cập vào quản lý ứng dụng của bạn. Thường thì đó là những người trong đội phát triển ứng dụng hoặc khách hàng. Số lượng tối đa cho internal tester là 25. Với mỗi lần bạn submit bản build lên App store connect hoàn thành, tất cả các internal tester sẽ nhận được thông báo về phiên bản mới nhất.
External tester: Đây là những người dùng không nằm trọng đội phát triển ứng dụng nhưng họn muốn trải nghiệm, kiểm thử ứng dụng của bạn. Các extenal tester không có quyền truy cập vào App store connect. Nhưng họ vẫn có thể tải và cài đặt phiên bản ứng dụng mà bạn muốn họ test. Hiện nay Apple đang giới hạn tối đa external tester là 10,000. Để external tester có thể cài đặt và kiểm thử ứng dụng của bạn thì bạn cần Submit bản build mà bạn muốn cho bên apple review gần giống như việc submit bản build lên app store. Khi bản build đó được approve thì tất cả các External tester sẽ nhận được thông báo và có thể tải và cài đặt ứng dụng dựa trên bản build đó.
Internal testers
Để thêm một internal tester bạn cần truy cập vào App store connect đăng nhập và truy cập vào mục Users and Assess
Bấm vào dấu + để thêm mới một user:
Điền đầy đủ thông tin và bấm invite để gửi email mời họ.
Lưu ý: Mục email là tài khoản apple(apple id) vì vậy những người muốn vào nhóm internal tester phải có tài khoản apple. Khi bạn add user này vào đồng nghĩa họ cũng sẽ có quyền truy cập vào App store connect để quản lý ứng dụng của bạn. Vì vậy hãy chú ý mục phân quyền(Role) cho user mà bạn muốn add.
App store connect sẽ gửi một thư mời tới user mà bạn vừa thêm. User này cần truy cập vào hòm thư của họ để mở thư mời và chọn Active your account.
Khi đó bạn sẽ được điều hướng sang trang của apple và bạn đăng nhập vào để active tài khoản của bạn. Hoàn thành bước này là bạn đã add tài khoản đó vào App store connect.
Nhưng để các tài khoản này có thể tải và cài đặt những bản build trên Testflight các bạn cần mời họ vào nhóm App store connect users(Internal tester). Vì vậy chúng ta sẽ chuyển qua mục My app
Một danh sách các ứng dụng của bạn được hiện ra. Hãy chọn ứng dụng mà bạn đang muốn quản lý. Chuyển sang tab Testflight > App store connect user > bấm dấu + để thêm user vào App store connect user.
Lúc này một danh sách các user hiện ra. Bạn hãy chọn User lúc trước bạn đã invite ở bước trên và bấm Add để Testflight gửi thư mời cho tài khoản đó.
Thư mời sẽ nằm trọng hòm thư của người dùng mà bạn vừa gửi. Bấm vào View In Testflight và hoàn thành các bước đơn giản để hoàn tất việc add Internal tester. Thư mời có định dạng như sau:
Vậy là hoàn tất việc add Internal tester. Từ giờ mỗi khi có bản build mới được upload lên TestFlight là người dùng này sẽ nhận được cả mail và thông báo.
External testers
Như đã giới thiệu ở trên, external tester là những user không thể truy cập vào App store connect của bạn nên chúng ta cần cung cấp thông tin bản kiểm thử cũng như cần chọn bản build cho apple review.
Cập nhật thông tin kiểm thử
Bạn mở mục Test information và điền đầy đủ các thông tin cho bản kiểm thử này. Nó là bắt buộc nên bạn cần phải điền đầy đủ thông tin cho nó. Nhớ bấm Save để lưu lại thông tin nhé.
Hãy điền đầy đủ thông tin cho mục Test information
Tạo nhóm External tester
Chọn mục Add Group để thêm mới nhóm External testers:
Đặt tên nhóm > Bấm Create để tạo nhóm tester mới.
Khi tạo thành công sẽ hiển thị một giao diện như dưới
Do nhóm vừa tạo nên chưa có tester nào. Để thêm tester chúng ta bấm vào dấu +
Add new testers: Đây là cách thêm thủ công, sử dụng khi ban muốn thêm số lượng ít tester
Add existing testers: Thêm các tester đã từng test ứng dụng rồi
Import from CSV: Sử dụng file CSV để thêm tester, sử dụng khi bạn muốn thêm số lượng lớn các tester
Ở bài này mình sẽ chỉ nói đến Add New Testers. Bạn điền thông tin của tester và bấm add để invite họ vào group.
Lúc này 1 thư mời sẽ được gửi tới hòm thư của email đó họ chỉ cần accept là được.
Chọn bản build dành cho external tester
Chuyển sang mục Builds và bấm vào dấu + để chọn bản build bạn muốn external tester kiểm thử.
Một danh sách các bản build được hiển thị, chọn bản mà bạn muốn test. Và bấm Add
Lúc này bạn đã Add thành công, giờ chờ để apple review.
Lúc này trạng thái của bản build đang là waiting for review có nghĩa là ứng dụng của bạn đang trong hàng đợi để nhân viên của apple review. Để được approve bản build của bạn phải không vi phạm điều luật apple đã đưa ra trong App Store Review Guideline. Việc review sẽ tốn một khoảng thời gian lớn tùy thuộc vào ứng dụng của bạn và thời gian bạn submit. Tuy nhiên một khi Apple đã approve cho version của bạn thì những bản build tiếp theo sẽ không phải review cho đến khi bạn thay đổi version.
Sau khi apple họ Approve bản build của bạn, một thông báo sẽ được gửi cho tất cả các tester trong nhóm. Để họ có thể tài và cài ứng dụng lên thiết bị của họ.
Vậy là chúng ta đã hoàn thành việc tạo nhóm external tester và thêm bản build cho nhóm external tester.
Tester cần làm gì?
Tải ứng dụng TestFlight trên App store
Khi có bản mới thông báo sẽ báo về mail các bạn chỉ cần bấm vào để sử dụng. Khi đó bạn sẽ được chuyển qua ứng dụng TestFlight và có thể Tải cũng như cài đặt ứng dụng.
Tổng kết
Bài viết này mình đã chia sẻ với các bạn về cách thêm internal tester, external tester để hỗ trợ việc tester kiểm thử ứng dụng. Hi vọng nó giúp các bạn phần nào bớt bỡ ngỡ khi tiếp cận TestFilght.
Như các bạn đã biết, Static Type Checking giúp chúng ta kiểm soát kiểu dữ liệu tốt hơn khi viết mã nguồn. Các bạn có thể sử dụng Flow hoặc TypeScript đều được. Tuy nhiên khi dữ liệu được liên kết với API chẳng hạn, khi đó bạn không thể kiểm soát được giá trị được truyền vào cho biến nào đó. Do đó chúng ta vẫn cần thêm một bước nữa để hạn chế các lỗi tiềm ẩn bằng Runtime Type Checking. Trong bài viết này tôi sẽ hướng dẫn các bạn sử dụng Runtime Type Checking như thế nào cho hiệu quả.
Runtime Type Checking là gì?
Runtime Type Checking là quá trình xác minh lại kiểu dữ liệu của giá trị truyền vào cho biến có đúng với kiểu dữ liệu mong muốn hay không. Trong ứng dụng React khi bạn khai báo propTypes cho component nào đó chính là lúc bạn đang định nghĩa kiểu dữ liệu mong muốn. Tại thời điểm thực thi các định nghĩa này sẽ được kiểm tra giúp bạn kiểm soát việc binding dữ liệu từ API vào component có tương thích với nhau hay không.
Định nghĩa propTypes
React cung cấp gói prop-types giúp bạn định nghĩa các thuộc tính cần cho Runtime Type Checking. Trước đây thì gói này nằm trong React, hiện tại thì nó đã tách ra thành một gói riêng rồi. Các bạn khai báo propTypes như sau:
Nếu số lượng thuộc tính trong component này tăng lên thì việc viết mã nguồn sẽ khá là vất vả. Rất may là trong JSX cung cấp cho bạn tính năng Spead Attributes và bạn có thể viết code như sau:
Các bạn có thấy rằng khi khai báo Octocat component tôi đã truyền props như làm tham số của một hàm và sau đó mới gán lại vào các biến. Với Destructuring Props bạn có thể viết mã nguồn đơn giản hơn như sau:
import React from 'react';
import PropTypes from 'prop-types';
export function Octocat({ login, avatar_url, name }) {
return (
<ul>
<li>{login}</li>
<li>{name}</li>
<li>
<img src={avatar_url} alt={login} />
</li>
</ul>
);
}
Octocat.propTypes = {
login: PropTypes.string,
avatar_url: PropTypes.string,
name: PropTypes.string
};
Một trọng những vấn đề quan trọng trong các dự án đó là điều khiển quyền truy cập. Với các ứng dụng xây dựng trên nền tảng AWS việc điều khiển truy cập cũng phức tạp hơn. Trong bài viết này tôi sẽ hướng dẫn các bạn cách tôi đã làm để điểu khiển truy cập với các API sử dụng API Gateway Lambda Authorizers.
Luồng xác thực Lambda Authorizer
Luồng xác thực của Lambda Authorizer được minh hoạ trong hình sau:
Các bược xác thực như sau:
Máy khách gửi yêu cầu lên API Gateway API có kèm theo Bearer Token.
API Gateway kiểm tra cấu hình authorizer đã được cấu hình tương ứng với hàm Lambda. Nếu nó tồn tại thì Lambda Authoirizer sẽ được gọi.
Lambda Authorizer sẽ thực hiện xác thực bằng Bearer Token đã được gửi lên.
Nếu việc gọi Lambda Authrorizer thực hiện thành công, hàm Lambda sẽ trả về thông tin chứa chính sách IAM và thông tin người dùng.
API Gateway sử dụng thông tin trả về từ Lambda Authorizer để kiểm tra quyền truy cập:
Trường hợp nhận được thông tin từ chối truy cập thì API Gateway sẽ trả về mã 403 và từ chối truy cập tới API từ máy khách.
Trường hợp nhận được thôn tin cho phép truy cập thì phương thức sẽ được thực thi.
import jwt
def lambda_handler(event, context):
try:
token = event.get("authorizationToken").split(" ")[1] # lấy thông tin token trong Authorization header
claims = jwt.decode(token, "secret", algorithms=["HS256"]) # decode xem token có hợp lệ không
return {
"principalId": claims["uid"], # lấy thông tin user đề gán vào IAM
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow", # cho phép nếu token hợp lệ
"Resource": event["methodArn"],
}
],
},
}
except:
return {
"principalId": "denied",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Deny", # từ chối nếu token không hợp lệ
"Resource": event["methodArn"],
}
],
},
}
Định nghĩa hàm Lambda cần điều khiển quyề truy cập
Trường hợp không truyền token trên Authorizer Header, API Gateway sẽ trả về 403
Trường hợp có truyền token trên Authorization Header, API Gateway sẽ cho phép phương thức được thực thi
Token được tạo như sau
(zpn) hieunv@HieuNV lambda % python
Python 3.7.7 (default, Mar 10 2020, 15:43:33)
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import jwt
>>> jwt.encode({'uid': 'hieunv'}, "secret", algorithm='HS256')
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJoaWV1bnYifQ.xuZSlS_3lw6NvGvw_fQ2qXGBWiv2HpXTFtYtO85lQac'
Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết có thể giúp các bạn cài đặt việc điều khiển truy cập dễ dàng hơn với các ứng dụng trên nền tảng AWS.
Có thể các bạn đã biết progress view của Apple nó khá là đơn giản và ýt thuộc tính để chúng ta có thể sử dụng cũng như thay đổi để phù hợp với thiết kế. Trong dự án gần đây mình đã có cơ hội để động vào nó. Trong thời gian đầu mình tự mày mò thì progress bar không hỗ trợ việc như vậy. Vì vậy mình viết bài này để chia sẻ về cách mình đã custom lại progress này. Hi vọng nó giúp các bạn gặp khó khăn với việc custom lại progress bar.
Vấn đề cần giải quyết: Làm thế nào để bo tròn góc của progress bar
Đây là progress view mình cần đạt được:
Đây là progress bar mặc đinh của apple:
Phân tích
Khi thử đọc tài liệu về UIProgressView. Không có thuộc tính nào giúp mình có thể đạt được điều mình muốn.
Để bo tròn cả progressview thì ta có thể dùng layer.cornerRadius, nhưng để bo tròn thằng progress chạy bên trong thì sao? Chúng ta cần tìm được cái view đó và bo nó lại.
Giải quyết bài toán
Bước 1: Chúng ta cần tạo constraint height cho progressView
Chúng ta có 2 cách để tăng height cho ProgressView: 1. Sử dụng Transform Scale: Nó sẽ làm cornerRadius chạy không đúng 2. Sử dụng constraint height: Nên chúng ta chon cách này
Tuy rằng chúng ta đã constraint height của nó bằng 16 nhưng thực tế height của progressView vẫn = 2. Vì vậy khi set cornerRadius chúng ta không thể sử dụng frame.height/2 được mặc dù đó là cách tốt nhất đối với các view khác.
if let sublayers = progressBar.layer.sublayers, sublayers.count > 1 {
sublayers[1].cornerRadius = 8.0
}
progressBar.subviews[1].clipsToBounds = true
Nếu để ý kĩ các bạn sẽ thấy progress bar này gồm 2 view chồng lên nhau đó là Progress View và track view. Và theo thứ tự trong lập trình thì thằng đầu tiên là thằng nằm dưới có index = 0. Chúng ta nhìn thấy progress view vì nó nằm trên Track View -> nó có index = 1
Lưu ý: Nó chỉ đúng khi chúng ta không thêm subview, sublayer cho ProgressView. Vậy nên trong trường hợp này chúng ta sẽ ổn.
If let giúp chúng ta handle trường hợp crash app, khi các layer của progress bị remove. (nó thường k xảy ra, nhưng vì an toàn chúng ta nên thêm dòng này)
sublayers[1]: là layer của track view subviews[1]: là trackView
Kết quả thu được thật mỹ mãn 😀
Ngoài ra các bạn có thể sử dụng image cho progress view cũng như trackView để có 1 progress đẹp hơn.
Static Type Checking và Runtime Type Checking là hai thuật ngữ ban đầu cảm giác có vẻ không quen thuộc cho nhưng nó lại lai thứ có lẽ các bạn đang dùng hàng ngày. Như các bạn biết thì JavaScript là ngôn ngữ định kiểu động, nghĩa là kiểu dữ liệu chỉ được xác định tại thời điểm thực thi. Do đó khi lập trình chúng ta không cần xác định kiểu dữ liệu cho biến. Điều này vô hình chung làm cho mã nguồn của chúng ta trở nên khó đọc hơn và khó debug hơn nữa. Chính vì vậy việc xác định kiểu dữ liệu giúp cho chúng ta kiểu soát và debug dễ dàng hơn. Trong bài viết này tôi sẽ chia sẻ với các bạn cách công đồng đang làm để hỗ trợ hai kiểu kiểm tra kiểu dữ liệu này.
Static Type Checking là gì?
Hiện nay có hai xu hướng để kiểm tra kiểu dữ liệu tĩnh là Flow và TypeScript. Static Type Checking sẽ phân tích mã nguồn tĩnh trước khi biên dịch mã nguồn sang mã JavsScript(ES5) là mã nguồn mà trình duyệt có thể đọc được. Vậy thì chúng khác nhau ở điểm nào?
Flow
Flow là một phần mở rộng của Babel cung cấp cho bạn việc kiểm tra kiểu dữ liệu tĩnh bằng cách sử dụng các chỉ thị bằng comment mà bạn thêm vào mã nguồn.
Ví dụ cách sử dụng flow như bên dưới:
// @flow
function square(n: number): number {
return n * n;
}
square('2'); // Error!
TypeScript
TypeScript là ngôn ngữ dựa trên JavaScript được Microsoft phát triển. TypeScript khác với Flow là nó không phân tích mã nguồn dự trên các chỉ thị bằng comment. Kiểu dữ liệu được hỗ trợ từ trong ngôn ngữ luôn. Dữ liệu được kiểm tra tại thời điểm phân tích cú pháp của chương trình dịch. Ngoài ra thì TypeScript hỗ trợ rất mạnh OOP nên nó rất phù hợp với các bạn quen thuộc với các ngôn ngữ định kiểu như Java và C#.
Khi sử dụng Static Type Checking bạn được hỗ trợ việc kiểm soát dữ liệu tại thời điểm viết mã nguồn, tất cả việc gán hoặc gọi hàm với kiểu dữ liệu không phù hợp sẽ được phát hiện tại thời điểm này.
IDE hỗ trợ việc kiểm soát kiểu dữ liệu giúp bạn viết code nhanh hơn và sai sốt ít hơn.
Mã nguồn dễ đọc hơn cho người mới.
Bạn mất gì khi sử dụng Static Type Checking?
Static Type Checking mang những lợi ích nhất định trong việc kiểm soát kiểu dữ liệu, tuy nhiên nó cũng có những nhiểm điểm:
Bạn phải viết code nhiều hơn thì mới kiểm soát được kiểu dữ liệu, việc này đương nhiên sẽ tốn công sức. Tuy nhiên so với việc mất thời gian vào debug thì có lẽ nó vẫn tốt hơn.
Bạn vẫn không kiểm soát được kiểu dữ liệu tại thời điểm chạy chương trình, lý do là nếu chương trình của bạn có liên kết với API thì không có gì đảm bảo kiểu dữ liệu của bạn chạy đúng với backend cả. Đương nhiên cái này là vấn đề không thể giải quyết được rồi. Tôi sẽ hướng dẫn các bạn giải quyết vấn đề này trong bài viết Runtime Type Checking sau nhé.
Kết luận
Đây chỉ là kết luận mang tính cá nhân của mình :). Các bạn tự suy ngẫm để đưa ra lựa chọn phù hợp nhé.
Việc viết theo Flow có cảm giác không tự nhiên lắm, thường xuyên phải thêm comment khiến bạn khá mất thời gian. Thêm một vấn đề nữa là lúc viết code sử dụng Flow khá tốn tài nguyên của máy. Về vấn đề này thì mình thấy TypeScript có vẻ ổn hơn.
TypeScript không đơn giản là một sự mở rộng của JavaScript, Microsoft đã thêm vào nhiều thứ hơn thế và nó cũng không dựa trên các tiêu chuẩn của ES6, ES7, … (có support ES6, ES7, … nhưng có những thêm vào nhiều thứ khác nữa). Về điểm này thì Flow có vẻ tốt hơn.
Sau sự ra đời của React Hooks thì mọi thế mạnh của TypeScript gần như không còn nữa so với Flow, bản thân mình cũng không dùng TypeScript nữa.
Một điểm quan trong nữa là cả TypeScript và Flow đều không thể xác mình kiểu dữ liệu lúc thực thi nên bạn vẫn cần Runtime Type Checking.
Các bạn có dùng Static Type Checking không? Mình thì đã không dùng nữa và chuyển sang xác mình toàn bộ bằng Runtime Type Checking rồi. Thời gian tốn cho debug cũng không phát sinh nhiều so với việc phải viết mã nguồn xác định kiểu dữ liệu.
Cảm ơn các bạn đã theo dõi bài viết. Các bạn cùng chờ bài viết mình hướng dẫn về Runtime Type Checking nhé.
Bước 1: Đăng nhập vào App store connect App store connect là trang quản lý ứng dụng của bạn trên store của apple. Để truy cập vào trang này chúng ta đăng nhập tài khoản Apple ID vào App store connect Đăng nhập thành công chúng ta sẽ có giao diện như hình dưới:
Bước 2: Chọn My Apps để sang màn hình quản lý ứng dụng của bạn.
Bước 3: Chọn + sau đó chọn New App
Bước 4: Điền đầy đủ thông tin liên quan đến ứng dụng của bạn.
Platforms: Ứng dụng bạn tạo chạy trên nền tảng nào?
Name: Đây là tên ứng dụng của bạn
Primary language: Ngôn ngữ mặc định mà người dùng nhìn thấy là gì? Nếu ứng dụng của các bạn chỉ phát hành 1 ngôn ngữ cho 1 quốc gia thì bạn chọn ngôn ngữ mà Ứng dụng đang sử dụng. Nếu ứng dụng của bạn phát hành trên toàn thế giới, mình nghĩ bạn nên chọn là Tiếng Anh vì khi ngôn ngữ máy của người dùng không nằm trong danh sách ngôn ngữ các bạn hỗ trợ nó sẽ hiển thị Tiếng Anh.
Bundle ID: Đây là bundle ID của ứng dụng của bạn. Nó phải khớp với Bundle ID bạn sử dụng trong XCode.
SKU: Viết tắt của Stock-Keeping Unit nó giúp apple quản lý kho ứng dụng của họ khi bạn upload ứng dụng của bạn lên store. Nó phải là duy nhất nên mình hay dùng trùng với Bundle Id.
User Access: Quyền truy cập vào quản lý ứng dụng này
Điền đầy đủ thông tin và bấm vào nút Create để tạo mới ứng dụng.
Bước 4: Chọn loại ứng dụng Bạn hãy chọn category đúng với ứng dụng của bạn
Cập nhật thông tin ứng dụng cho phiên bản mới
Bước 1: Chọn tab iOS App > 1.x Prepare for Submission > Cập nhật thông tin phiên bản mới (nếu đây không phải là bản đầu tiên)
Bước 2: Cập nhật bộ ảnh giới thiệu ứng dụng của bạn. Ảnh phải có định dạng là JPG hoặc PNG. và sử dụng dạng màu RGB. Video Preview chỉ chấp nhận định dạng M4v, MP4 hoặc MOV và không vượt quá 500MB
Apple yêu cầu bạn phải có ýt nhất 5 ảnh giới thiệu về ứng dụng của bạn. Nếu ứng dụng của bạn chỉ hỗ trợ Iphone thì bạn cần chuẩn bị 5 hình cho Iphone 6.5 Display và 5 hình cho Iphone 5.5 Display. Nếu có hỗ trợ Ipad thì cần thêm 5 hình cho Ipad 12.9 Display Cụ thể kích thước các bạn xem ở link này.
Bước 3: Nhập thông tin ứng dụng của bạn
Promotional text: là đoạn text quảng cáo cho phép bạn thông báo tới người dùng truy cập App store của mình về bất cứ tính năng ứng dụng nào mà không yêu cầu gửi cập nhật. Nó sẽ xuất hiện phía trên mô ta của bạn trên appstore và chỉ dành cho khách hàng sử dụng iOS 11 trở lên và macOS 10.13 trở lên.
Keywords: Là chuuỗi những từ khóa mà bạn muốn người dùng tìm thấy ứng dụng của bạn.
Description: Mô tả về ứng dụng của bạn.
Support URL: Link hỗ trợ
Bước 4: Cập nhật thông tin chung của ứng dụng
App store icon: Đây là icon ứng dụng của bạn yêu cầu kích thước 1024×1024
Copyright: Thường là tên cty
sign-in required: Nếu ứng dụng của bạn yêu cầu Login mới sử dụng được hãy tích vào và điền thông tin USername password để nhân viên apple review.
Bước 5: Chọn dạng release
Bạn có thể chọn tự động release ứng dụng khi nhân viên của Apple chấp thuận ứng dụng của bạn. Hoặc chọn ngày để release
Bước 6: Bấm save – Bước quan trọng nhất =))
Bước 7: Chọn file build cho phiên bản này để nhân viên của apple review.
Bâm dấu + để chọn bản build mà bạn muốn apple review
Bản build mà bạn chọn cho apple review chính là bản được xuât hiện trên store.
Nếu bạn chưa up bản nào lên thì hãy đọc tiếp bước dưới đây.
Cách tạo file build trên XCode
Chuẩn bị trước khi Archive:
Bạn cần tăng version của app nếu đây là bản release tiếp theo của bản trước đó: Ví dụ: Nếu bản trên store đang là 1.0 thì version của bản này phải > 1.0
Bạn cần tăng bản build của version app: Với mỗi 1 version apple yêu cầu các build version mới phải > build version cũ. Ví dụ: Nếu Bản testflight của bạn đang là 1.0 (1) thì bạn cần tăng build cho nó lớn hơn(1)
Nếu không để ý các bước chuẩn bị, khi upload lên xcode sẽ thông báo lỗi và lúc đó các bạn sẽ phải archive lại từ đầu. Sẽ mất rất nhiều thời gian nên hãy cẩn thận ở bước này.
Để thay đổi version và build version của app bạn chọn App Target > General
Để Archive ứng dụng bạn chọn Product > Archive Lưu ý: Archive bị disable khi sử dụng device là similator(máy ảo) vì vậy bạn cần chọn máy thật hoặc chọn Generic iOS Device
Khi Archive thành công sẽ hiển thị popup quản lý file Archive. Nếu bạn lỡ tay tắt pop up thì có thể mở lại bằng cách Chọn Window > Organizer
Ở đây bạn chọn Automatically manage signing để xcode tự động tạo hoặc update certificate cho bạn. > Next Hoặc bạn cũng có thế chọn bằng tay
Màn hình review file ipa của bạn được hiển thị ra: Lúc này bấm > Upload
Chờ đợi apple verify file ipa của bạn. Khi này có thể xảy ra 2 trường hợp
Apple trả về lỗi: Copy lỗi paste lên google là có ng trả lời giúp nhé
Apple trả về thành công: Bạn đã đẩy được file lên testflight và phải chờ khoảng 15 phút để file ipa đó có thể hoạt động được. Khi nào file ipa sẵn sàng sẽ có thông báo tới các tài khoản test được đăng ký ở Testflight.
Lúc này bạn quay lại trang App Store connect để kiểm tra trạng thái.
Lúc này hãy đi pha 1 tách trà và chờ đợi. Uống xong trà là nó sẽ xong ấy mà :)). Bao giờ nó chuyển sang Ready to test thì bạn có thể sử dụng để đẩy lên store.
Tuy nhiên để đảm bảo an toàn cho từng bản build, với mỗi bản build này bạn cần xây dụng một file checklist để kiểm tra 1 loạt các tính năng chính của ứng dụng trước khi Submit to review
Tiếp theo bạn quay lại bước 7 ở trên. Chọn file vừa mới upload lên.
Vậy là hoàn tất các bước chuẩn bị. Giờ chúng ta bấm Submit for Review
Vậy là các bạn đã hoàn tất việc đẩy ứng dụng lên store.
Sau 1 khoảng thời gian từ 1 -> x ngày để apple review ứng dụng của ban. Nếu cuối tuần nó sẽ lâu hơn vì cuối tuần là ngày nghỉ nhân viên nó k làm việc Lúc này sẽ có 2 trường hợp xảy ra
Apple reject bản build của bạn: Vì có thể bạn vi phạm chính sách nghiêm ngặt mà apple đã đặt ra. Hãy đọc bài App Store Review Guideline để không bị reject.
Apple Approve bản build của bạn: Xin chúc mừng bạn đã đẩy lên store thành công.
Tổng kết
Vậy là mình đã hướng dẫn các bạn upload thành công 1 ứng dụng lên store. Chúc các bạn thành công!