Tích hợp iOS
EContractSDK Native iOS là SDK cho phép tích hợp mô-đun Flutter eContract vào ứng dụng iOS native một cách dễ dàng. SDK cung cấp các phương thức tương tự như EContractInterface trong Flutter SDK để khách hàng có thể tương tác với Flutter module từ native iOS.
- iOS 13.0 trở lên
- Xcode 15.0 trở lên
- Swift 5.9 trở lên
Bước 1: Tải SDK và cấu hình Project
- 1.1. Tải SDK
Tải file EContractSDK.xcframework và các Flutter frameworks từ bản phát hành
1.2. Thêm Framework vào Xcode Project
Mở Xcode project của bạn
Chọn target của ứng dụng
Vào tab General → Frameworks, Libraries, and Embedded Content
Click + và chọn Add Other... → Add Files...
Chọn các framework sau:
EContractSDK.xcframeworkEContractApp.frameworkEContractFlutter.frameworkFlutterPluginRegistrant.xcframework(nếu có)
Đảm bảo tất cả frameworks được set là Embed & Sign
- 1.3. Cấu hình Build Settings
Vào tab Build Settings
Tìm Framework Search Paths và thêm:
$(PROJECT_DIR)/path/to/Flutter/Release-iphoneos
$(PROJECT_DIR)/path/to/Flutter/Release-iphonesimulator
Tìm Other Linker Flags và thêm:
-framework Flutter
-framework App
- 1.4. Cấu hình Info.plist
Thêm quyền cần thiết vào Info.plist (nếu chưa có):
<key>NSPhotoLibraryUsageDescription</key>
<string>Cần truy cập thư viện ảnh để chọn tài liệu</string>
<key>NSCameraUsageDescription</key>
<string>Cần truy cập camera để chụp ảnh tài liệu</string>
Bước 2: Khởi tạo SDK tại nơi bắt đầu kết nối
- 2.1. Import Framework
Thêm import vào file Swift nơi bạn muốn sử dụng SDK:
import EContractSDK
- 2.2. Khởi tạo SDK trong AppDelegate hoặc SceneDelegate
Khởi tạo SDK một lần khi ứng dụng khởi động, tốt nhất là trong application(_:didFinishLaunchingWithOptions:) hoặc scene(_:willConnectTo:options:):
import UIKit
import EContractSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Khởi tạo SDK với cấu hình
let config: [String: Any] = [
"token": "your_access_token",
"clientId": "your_client_id",
"clientSecret": "your_client_secret",
"khachHangId": 12345,
"locale": "vi", // hoặc "en"
"env": "PROD" // hoặc "DEV", "STAG"
]
EContractSDK.initialize(config: config)
return true
}
}
Hoặc trong SceneDelegate (iOS 13+):
import UIKit
import EContractSDK
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
// Khởi tạo SDK
let config: [String: Any] = [
"token": "your_access_token",
"clientId": "your_client_id",
"clientSecret": "your_client_secret",
"khachHangId": 12345,
"locale": "vi",
"env": "PROD"
]
EContractSDK.initialize(config: config)
// ... rest of your code
}
}
- 2.3. Tham số cấu hình
| Tham số | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
| token | String | Có | Access token để xác thực |
| clientId | String | Có | Client ID của ứng dụng |
| clientSecret | String | Có | Client Secret của ứng dụng |
| khachHangId | Int | Có | ID khách hàng |
| locale | String | Không | Ngôn ngữ: "vi" hoặc "en" (mặc định: "vi") |
| env | String | Không | Môi trường: "STAG" hoặc "PROD" (mặc định: "PROD") |
Bước 3: Sử dụng các hàm chính
- 3.1. Launch SDK (Màn hình mặc định)
- Mở SDK với màn hình mặc định:
import EContractSDK
class ViewController: UIViewController {
@IBAction func launchSDK(_ sender: UIButton) {
EContractSDK.launch(from: self) { result in
self.handleResult(result)
}
}
private func handleResult(_ result: EContractSDKResult) {
switch result {
case .success(let data):
print("Success: \(data)")
case .failure(let error):
print("Error: \(error)")
}
}
}
- 3.2. Điều hướng đến danh sách hợp đồng đến
EContractSDK.navigateToIncomingContracts(from: self) { result in
switch result {
case .success(let data):
// Xử lý kết quả thành công
print("Hợp đồng đến: \(data)")
case .failure(let error):
// Xử lý lỗi
print("Lỗi: \(error)")
}
}
- 3.3. Điều hướng đến danh sách hợp đồng đi
EContractSDK.navigateToOutgoingContracts(from: self) { result in
switch result {
case .success(let data):
print("Hợp đồng đi: \(data)")
case .failure(let error):
print("Lỗi: \(error)")
}
}
- 3.4. Điều hướng đến chi tiết hợp đồng
// Với contractId
EContractSDK.navigateToContractScreen(
from: self,
contractId: "contract_123",
documentFileId: nil,
isLoginNoAccount: nil
) { result in
switch result {
case .success(let data):
print("Chi tiết hợp đồng: \(data)")
case .failure(let error):
print("Lỗi: \(error)")
}
}
// Với contractId và documentFileId
EContractSDK.navigateToContractScreen(
from: self,
contractId: "contract_123",
documentFileId: "doc_456",
isLoginNoAccount: "false"
) { result in
// Xử lý kết quả
}
- 3.5. Điều hướng đến màn hình ký hợp đồng
// Ký hợp đồng (không có documentFileId - ký toàn bộ hợp đồng)
EContractSDK.navigateToSignContract(
from: self,
contractId: "contract_123",
documentFileId: nil,
isLoginNoAccount: "false"
) { result in
switch result {
case .success(let data):
print("Ký hợp đồng thành công: \(data)")
case .failure(let error):
print("Lỗi ký hợp đồng: \(error)")
}
}
// Ký file cụ thể trong hợp đồng
EContractSDK.navigateToSignContract(
from: self,
contractId: "contract_123",
documentFileId: "doc_456",
isLoginNoAccount: "false"
) { result in
// Xử lý kết quả
}
- 3.6. Điều hướng đến thông tin chữ ký
EContractSDK.navigateToSignatureInfo(
from: self,
contractId: "contract_123",
documentFileId: "doc_456",
isLoginNoAccount: nil
) { result in
switch result {
case .success(let data):
print("Thông tin chữ ký: \(data)")
case .failure(let error):
print("Lỗi: \(error)")
}
}
📦 Tất cả các phương thức đều trả về EContractSDKResult:
public enum EContractSDKResult {
case success([String: Any]) // Thành công, kèm dữ liệu
case failure(EContractSDKError) // Lỗi
}
public enum EContractSDKError: Error {
case invalidHost // Host không hợp lệ
case flutterNotReady // Flutter chưa sẵn sàng
case cancelled // Người dùng hủy
case message(String) // Lỗi với thông báo
}
Ví dụ xử lý:
EContractSDK.launch(from: self) { result in
switch result {
case .success(let data):
// Xử lý dữ liệu trả về
if let contractId = data["contractId"] as? String {
print("Contract ID: \(contractId)")
}
case .failure(let error):
switch error {
case .cancelled:
print("Người dùng đã hủy")
case .flutterNotReady:
print("Flutter chưa sẵn sàng, vui lòng thử lại")
case .invalidHost:
print("Host không hợp lệ")
case .message(let msg):
print("Lỗi: \(msg)")
}
}
}
Ví dụ hoàn chỉnh
import UIKit
import EContractSDK
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
private func setupUI() {
// Tạo các button để test các chức năng
let launchButton = UIButton(type: .system)
launchButton.setTitle("Launch SDK", for: .normal)
launchButton.addTarget(self, action: #selector(launchSDK), for: .touchUpInside)
// ... thêm các button khác
}
@objc private func launchSDK() {
EContractSDK.launch(from: self) { [weak self] result in
self?.handleResult(result)
}
}
private func handleResult(_ result: EContractSDKResult) {
let alert: UIAlertController
switch result {
case .success(let data):
alert = UIAlertController(
title: "Thành công",
message: "Dữ liệu: \(data)",
preferredStyle: .alert
)
case .failure(let error):
alert = UIAlertController(
title: "Lỗi",
message: "\(error)",
preferredStyle: .alert
)
}
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}
Lỗi: "Framework not found EContractSDK"
Giải pháp:
Kiểm tra Framework Search Paths trong Build Settings
Đảm bảo framework đã được thêm vào "Embed & Sign"
Clean build folder (Shift + Cmd + K) và build lại
"Flutter not ready"
Giải pháp:
Đảm bảo đã gọi
EContractSDK.initialize(config:)trước khi sử dụngKiểm tra các Flutter frameworks đã được embed đúng chưa
Lỗi: "dyld: Library not loaded"
Giải pháp:
Kiểm tra tất cả frameworks đã được set "Embed & Sign"
Kiểm tra Framework Search Paths
Thử clean và rebuild project
Changelog
Version 1.0.0
Initial release
Hỗ trợ các chức năng cơ bản: launch, navigate to contract lists, contract detail, sign contract, signature info