7. Sử dụng Python trên iOS¶
- tác giả:
Russell Keith-Magee (2024-03)
Python trên iOS không giống Python trên nền tảng máy tính để bàn. Trên nền tảng máy tính để bàn, Python thường được cài đặt làm tài nguyên hệ thống có thể được sử dụng bởi bất kỳ người dùng máy tính đó. Sau đó, người dùng tương tác với Python bằng cách chạy tệp thực thi python và nhập lệnh tại dấu nhắc tương tác hoặc bằng cách chạy tập lệnh Python.
Trên iOS, không có khái niệm cài đặt làm tài nguyên hệ thống. Đơn vị phân phối phần mềm duy nhất là "ứng dụng". Cũng không có bảng điều khiển nào nơi bạn có thể chạy tệp thực thi python hoặc tương tác với Python REPL.
Do đó, cách duy nhất bạn có thể sử dụng Python trên iOS là ở chế độ nhúng - nghĩa là bằng cách viết một ứng dụng iOS gốc và nhúng trình thông dịch Python bằng libPython và gọi mã Python bằng Python embedding API. Sau đó, trình thông dịch Python đầy đủ, thư viện chuẩn và tất cả mã Python của bạn được đóng gói dưới dạng một gói độc lập có thể được phân phối qua iOS App Store.
Nếu bạn đang muốn thử nghiệm lần đầu tiên viết ứng dụng iOS bằng Python, các dự án như BeeWare và Kivy sẽ cung cấp trải nghiệm người dùng dễ tiếp cận hơn nhiều. Các dự án này quản lý sự phức tạp liên quan đến việc chạy một dự án iOS, vì vậy bạn chỉ cần xử lý chính mã Python.
7.1. Python khi chạy trên iOS¶
7.1.1. Khả năng tương thích phiên bản iOS¶
Phiên bản iOS được hỗ trợ tối thiểu được chỉ định tại thời điểm biên dịch, sử dụng tùy chọn --host cho configure. Theo mặc định, khi biên dịch cho iOS, Python sẽ được biên dịch với phiên bản iOS được hỗ trợ tối thiểu là 13.0. Để sử dụng phiên bản iOS tối thiểu khác, hãy cung cấp số phiên bản như một phần của đối số --host - ví dụ: --host=arm64-apple-ios15.4-simulator sẽ biên dịch bản dựng trình mô phỏng ARM64 với mục tiêu triển khai là 15.4.
7.1.2. Nhận dạng nền tảng¶
Khi thực thi trên iOS, sys.platform sẽ báo cáo là ios. Giá trị này sẽ được trả về trên iPhone hoặc iPad, bất kể ứng dụng đang chạy trên trình mô phỏng hay thiết bị vật lý.
Bạn có thể lấy thông tin về môi trường thời gian chạy cụ thể, bao gồm phiên bản iOS, kiểu thiết bị và liệu thiết bị đó có phải là trình mô phỏng hay không bằng cách sử dụng platform.ios_ver(). platform.system() sẽ báo cáo iOS hoặc iPadOS, tùy thuộc vào thiết bị.
os.uname() báo cáo chi tiết cấp hạt nhân; nó sẽ báo tên là Darwin.
7.1.3. Tính khả dụng của thư viện tiêu chuẩn¶
Thư viện chuẩn Python có một số thiếu sót và hạn chế đáng chú ý trên iOS. Xem API availability guide for iOS để biết chi tiết.
7.1.4. Các mô-đun mở rộng nhị phân¶
Một điểm khác biệt đáng chú ý về iOS với tư cách là một nền tảng là việc phân phối App Store áp đặt các yêu cầu cứng nhắc đối với việc đóng gói ứng dụng. Một trong những yêu cầu này chi phối cách phân phối các mô-đun mở rộng nhị phân.
Cửa hàng ứng dụng iOS yêu cầu các mô-đun nhị phân all trong ứng dụng iOS phải là thư viện động, được chứa trong một khung có siêu dữ liệu thích hợp, được lưu trữ trong thư mục Frameworks của ứng dụng đóng gói. Chỉ có thể có một tệp nhị phân duy nhất cho mỗi khung và không thể có tài liệu nhị phân thực thi nào bên ngoài thư mục Frameworks.
Điều này mâu thuẫn với cách tiếp cận Python thông thường để phân phối tệp nhị phân, cho phép tải mô-đun mở rộng nhị phân từ bất kỳ vị trí nào trên sys.path. Để đảm bảo tuân thủ các chính sách của App Store, dự án iOS phải xử lý hậu kỳ mọi gói Python, chuyển đổi mô-đun nhị phân .so thành các khung độc lập riêng lẻ với siêu dữ liệu và ký kết phù hợp. Để biết chi tiết về cách thực hiện quá trình xử lý hậu kỳ này, hãy xem hướng dẫn dành cho adding Python to your project.
Để giúp Python khám phá các tệp nhị phân ở vị trí mới của chúng, tệp .so ban đầu trên sys.path được thay thế bằng tệp .fwork. Tệp này là tệp văn bản chứa vị trí của tệp nhị phân khung, liên quan đến gói ứng dụng. Để cho phép khung phân giải trở lại vị trí ban đầu, khung phải chứa tệp .origin chứa vị trí của tệp .fwork, liên quan đến gói ứng dụng.
Ví dụ: hãy xem xét trường hợp nhập from foo.bar import _whiz, trong đó _whiz được triển khai với mô-đun nhị phân sources/foo/bar/_whiz.abi3.so, với sources là vị trí được đăng ký trên sys.path, liên quan đến gói ứng dụng. Mô-đun must này được phân phối dưới dạng Frameworks/foo.bar._whiz.framework/foo.bar._whiz (tạo tên khung từ đường dẫn nhập đầy đủ của mô-đun), với tệp Info.plist trong thư mục .framework xác định tệp nhị phân làm khung. Mô-đun foo.bar._whiz sẽ được biểu thị ở vị trí ban đầu bằng tệp đánh dấu sources/foo/bar/_whiz.abi3.fwork, chứa đường dẫn Frameworks/foo.bar._whiz/foo.bar._whiz. Khung này cũng sẽ chứa Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin, chứa đường dẫn đến tệp .fwork.
Khi chạy trên iOS, trình thông dịch Python sẽ cài đặt AppleFrameworkLoader có khả năng đọc và nhập tệp .fwork. Sau khi được nhập, thuộc tính __file__ của mô-đun nhị phân sẽ báo cáo là vị trí của tệp .fwork. Tuy nhiên, ModuleSpec cho mô-đun đã tải sẽ báo cáo origin là vị trí của tệp nhị phân trong thư mục khung.
7.1.5. Các tệp nhị phân sơ khai của trình biên dịch¶
Xcode không hiển thị trình biên dịch rõ ràng cho iOS; thay vào đó, nó sử dụng tập lệnh xcrun để phân giải thành đường dẫn trình biên dịch đầy đủ (ví dụ: xcrun --sdk iphoneos clang để lấy clang cho thiết bị iPhone). Tuy nhiên, việc sử dụng tập lệnh này đặt ra hai vấn đề:
Đầu ra của
xcrunbao gồm các đường dẫn dành riêng cho máy, dẫn đến mô-đun cấu hình hệ thống không thể chia sẻ giữa những người dùng; vàNó dẫn đến các định nghĩa
CC/CPP/LD/ARbao gồm khoảng trắng. Có rất nhiều công cụ hệ sinh thái C giả định rằng bạn có thể phân chia một dòng lệnh ở khoảng trống đầu tiên để có được đường dẫn đến trình biên dịch có thể thực thi được; đây không phải là trường hợp khi sử dụngxcrun.
Để tránh những vấn đề này, Python đã cung cấp sơ khai cho các công cụ này. Các sơ khai này là các trình bao bọc tập lệnh shell xung quanh các công cụ xcrun cơ bản, được phân phối trong thư mục bin được phân phối cùng với khung iOS đã biên dịch. Các tập lệnh này có thể định vị lại và sẽ luôn phân giải theo đường dẫn hệ thống cục bộ thích hợp. Bằng cách đưa các tập lệnh này vào thư mục bin đi kèm với một khung, nội dung của mô-đun sysconfig sẽ trở nên hữu ích cho người dùng cuối trong việc biên dịch các mô-đun của riêng họ. Khi biên dịch các mô-đun Python của bên thứ ba cho iOS, bạn nên đảm bảo các tệp nhị phân sơ khai này nằm trên đường dẫn của bạn.
7.2. Cài đặt Python trên iOS¶
7.2.1. Công cụ xây dựng ứng dụng iOS¶
Xây dựng cho iOS yêu cầu sử dụng công cụ Xcode của Apple. Chúng tôi thực sự khuyên bạn nên sử dụng bản phát hành Xcode ổn định gần đây nhất. Điều này sẽ yêu cầu sử dụng phiên bản macOS được phát hành gần đây nhất (hoặc thứ hai), vì Apple không duy trì Xcode cho các phiên bản macOS cũ hơn. Công cụ dòng lệnh Xcode không đủ để phát triển iOS; bạn cần cài đặt Xcode full.
Nếu muốn chạy mã trên trình mô phỏng iOS, bạn cũng cần cài đặt Nền tảng mô phỏng iOS. Bạn sẽ được nhắc chọn Nền tảng mô phỏng iOS khi chạy Xcode lần đầu tiên. Ngoài ra, bạn có thể thêm Nền tảng mô phỏng iOS bằng cách chọn từ tab Nền tảng của bảng Cài đặt Xcode.
7.2.2. Thêm Python vào dự án iOS¶
Python có thể được thêm vào bất kỳ dự án iOS nào bằng cách sử dụng Swift hoặc Objective C. Các ví dụ sau sẽ sử dụng Objective C; nếu bạn đang sử dụng Swift, bạn có thể thấy thư viện như PythonKit sẽ hữu ích.
Để thêm Python vào dự án Xcode iOS:
Xây dựng hoặc lấy Python
XCFramework. Xem hướng dẫn trong Apple/iOS/README.md (trong bản phân phối nguồn CPython) để biết chi tiết về cách xây dựng PythonXCFramework. Tối thiểu, bạn sẽ cần một bản dựng hỗ trợarm64-apple-ios, cộng với một trongarm64-apple-ios-simulatorhoặcx86_64-apple-ios-simulator.Kéo
XCframeworkvào dự án iOS của bạn. Trong các hướng dẫn sau, chúng tôi sẽ cho rằng bạn đã thảXCframeworkvào thư mục gốc của dự án; tuy nhiên, bạn có thể sử dụng bất kỳ vị trí nào khác mà bạn muốn bằng cách điều chỉnh đường dẫn nếu cần.Thêm mã ứng dụng của bạn dưới dạng thư mục trong dự án Xcode của bạn. Trong các hướng dẫn sau, chúng tôi sẽ giả định rằng mã người dùng của bạn nằm trong thư mục có tên
apptrong thư mục gốc của dự án; bạn có thể sử dụng bất kỳ vị trí nào khác bằng cách điều chỉnh đường dẫn nếu cần. Đảm bảo rằng thư mục này được liên kết với mục tiêu ứng dụng của bạn.Chọn mục tiêu ứng dụng bằng cách chọn nút gốc của dự án Xcode của bạn, sau đó chọn tên mục tiêu trong thanh bên xuất hiện.
Trong cài đặt "Chung", trong "Khung, Thư viện và Nội dung được nhúng", hãy thêm
Python.xcframework, với "Nhúng & Ký" được chọn.Trong tab "Cài đặt bản dựng", sửa đổi các mục sau:
Tùy chọn xây dựng
Hộp cát tập lệnh người dùng: Không
Kích hoạt khả năng kiểm tra: Có
Đường dẫn tìm kiếm
Đường dẫn tìm kiếm khung:
$(PROJECT_DIR)Đường dẫn tìm kiếm tiêu đề:
"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"
Apple Clang - Cảnh báo - Tất cả ngôn ngữ
Được trích dẫn Bao gồm trong tiêu đề khung: Không
Thêm bước xây dựng xử lý thư viện chuẩn Python và các phần phụ thuộc nhị phân Python của riêng bạn. Trong tab "Xây dựng giai đoạn", thêm bước xây dựng "Chạy tập lệnh" mới before bước "Nhúng khung", nhưng after bước "Sao chép tài nguyên gói". Đặt tên cho bước "Xử lý thư viện Python", tắt hộp kiểm "Dựa trên phân tích phụ thuộc" và đặt nội dung tập lệnh thành:
đặt -e nguồn $PROJECT_DIR/Python.xcframework/build/build_utils.sh install_python Ứng dụng Python.xcframework
Nếu bạn đã đặt XCframework ở đâu đó ngoài thư mục gốc của dự án, hãy sửa đổi đường dẫn đến đối số đầu tiên.
Thêm mã Objective C để khởi tạo và sử dụng trình thông dịch Python ở chế độ nhúng. Bạn nên đảm bảo rằng:
chế độ UTF-8 (
PyPreConfig.utf8_mode) là enabled;Stdio đệm (
PyConfig.buffered_stdio) là disabled;Viết mã byte (
PyConfig.write_bytecode) là disabled;Bộ xử lý tín hiệu (
PyConfig.install_signal_handlers) là enabled;Ghi nhật ký hệ thống (
PyConfig.use_system_logger) là enabled (tùy chọn, nhưng đặc biệt khuyến khích; tính năng này được bật theo mặc định);PYTHONHOMEcho trình thông dịch được định cấu hình để trỏ đến thư mục conpythontrong gói ứng dụng của bạn; vàZz000zz dành cho trình thông dịch bao gồm:
thư mục con
python/lib/python3.Xcủa gói ứng dụng của bạn,thư mục con
python/lib/python3.X/lib-dynloadcủa gói ứng dụng của bạn vàthư mục con
appcủa gói ứng dụng của bạn
Vị trí gói ứng dụng của bạn có thể được xác định bằng
[[NSBundle mainBundle] resourcePath].
Bước 7 và 8 trong số hướng dẫn này giả định rằng bạn có một thư mục chứa mã ứng dụng Python thuần túy, có tên là app. Nếu bạn có mô-đun nhị phân của bên thứ ba trong ứng dụng của mình thì bạn sẽ phải thực hiện một số bước bổ sung:
Bạn cần đảm bảo rằng mọi thư mục chứa tệp nhị phân của bên thứ ba đều được liên kết với mục tiêu ứng dụng hoặc được sao chép rõ ràng như một phần của bước 7. Bước 7 cũng phải loại bỏ mọi tệp nhị phân không phù hợp với nền tảng mà bản dựng cụ thể đang nhắm mục tiêu (tức là xóa mọi tệp nhị phân của thiết bị nếu bạn đang xây dựng một ứng dụng nhắm mục tiêu trình mô phỏng).
Nếu bạn đang sử dụng một thư mục riêng cho các gói của bên thứ ba, hãy đảm bảo rằng thư mục đó được thêm vào cuối lệnh gọi tới
install_pythonở bước 7 và là một phần của cấu hìnhPYTHONPATHở bước 8.Nếu bất kỳ thư mục nào chứa gói của bên thứ ba sẽ chứa tệp
.pth, bạn nên thêm thư mục đó dưới dạng site directory (sử dụngsite.addsitedir()), thay vì thêm trực tiếp vàoPYTHONPATHhoặcsys.path.
7.2.3. Kiểm tra gói Python¶
Cây nguồn CPython chứa a testbed project được sử dụng để chạy bộ thử nghiệm CPython trên trình mô phỏng iOS. Nền tảng thử nghiệm này cũng có thể được sử dụng làm dự án thử nghiệm để chạy bộ thử nghiệm thư viện Python của bạn trên iOS.
Sau khi xây dựng hoặc có được XCFramework iOS (xem Apple/iOS/README.md để biết chi tiết), hãy tạo một bản sao của dự án thử nghiệm Python iOS. Nếu bạn đã sử dụng tập lệnh xây dựng Apple để xây dựng XCframework, bạn có thể chạy:
$ python cross-build/iOS/testbed clone --app <path/to/module1> --app <path/to/module2> app-testbed
Hoặc, nếu bạn đã tạo nguồn XCframework của riêng mình, bằng cách chạy:
$ python Bản sao Apple/testbed --platform iOS --framework <path/to/Python.xcframework> --app <path/to/module1> --app <path/to/module2> app-testbed
Bất kỳ thư mục nào được chỉ định bằng cờ --app sẽ được sao chép vào dự án thử nghiệm nhân bản. Bản thử nghiệm thu được sẽ được tạo trong thư mục app-testbed. Trong ví dụ này, module1 và module2 sẽ là các mô-đun có thể nhập được khi chạy. Nếu dự án của bạn có các phần phụ thuộc bổ sung, chúng có thể được cài đặt vào thư mục app-testbed/Testbed/app_packages (sử dụng pip install --target app-testbed/Testbed/app_packages hoặc tương tự).
Sau đó, bạn có thể sử dụng thư mục app-testbed để chạy bộ thử nghiệm cho ứng dụng của mình. Ví dụ: nếu module1.tests là điểm vào bộ thử nghiệm của bạn, bạn có thể chạy:
$ python chạy thử nghiệm ứng dụng -- module1.tests
Điều này tương đương với việc chạy python -m module1.tests trên bản dựng Python trên máy tính để bàn. Mọi đối số sau -- sẽ được chuyển đến vùng thử nghiệm như thể chúng là đối số của python -m trên máy tính để bàn.
Bạn cũng có thể mở dự án thử nghiệm trong Xcode bằng cách chạy:
$ mở ứng dụng-testbed/iOSTestbed.xcodeproj
Điều này sẽ cho phép bạn sử dụng bộ công cụ Xcode đầy đủ để gỡ lỗi.
Các đối số được sử dụng để chạy bộ thử nghiệm được xác định như một phần của kế hoạch thử nghiệm. Để sửa đổi kế hoạch kiểm tra, hãy chọn nút kế hoạch kiểm tra của cây dự án (nó phải là nút con đầu tiên của nút gốc) và chọn tab "Cấu hình". Sửa đổi giá trị "Đối số được truyền khi khởi chạy" để thay đổi đối số thử nghiệm.
Kế hoạch kiểm tra cũng vô hiệu hóa kiểm tra song song và chỉ định việc sử dụng tệp Testbed.lldbinit để cung cấp cấu hình của trình gỡ lỗi. Cấu hình trình gỡ lỗi mặc định vô hiệu hóa các điểm dừng tự động trên các tín hiệu SIGINT, SIGUSR1, SIGUSR2 và SIGXFSZ.
7.3. Tuân thủ App Store¶
Cơ chế duy nhất để phân phối ứng dụng cho thiết bị iOS của bên thứ ba là gửi ứng dụng tới iOS App Store; ứng dụng được gửi để phân phối phải vượt qua quy trình đánh giá ứng dụng của Apple. Quá trình này bao gồm một bộ quy tắc xác thực tự động để kiểm tra gói ứng dụng đã gửi để tìm mã có vấn đề. Có một số bước phải được thực hiện để đảm bảo rằng ứng dụng của bạn có thể vượt qua các bước xác thực này.
7.3.1. Mã không tương thích trong thư viện chuẩn¶
Thư viện chuẩn Python chứa một số mã được biết là vi phạm các quy tắc tự động này. Mặc dù những vi phạm này có vẻ là sai trái nhưng không thể thách thức các quy tắc đánh giá của Apple; vì vậy, cần phải sửa đổi thư viện chuẩn Python để một ứng dụng vượt qua bài đánh giá của App Store.
Cây nguồn Python chứa a patch file sẽ xóa tất cả mã được xác định là gây ra sự cố với quá trình xem xét trên App Store. Bản vá này được áp dụng tự động khi xây dựng cho iOS.
7.3.2. Bản kê khai quyền riêng tư¶
Vào tháng 4 năm 2025, Apple đã đưa ra yêu cầu đối với certain third-party libraries to provide a Privacy Manifest. Do đó, nếu bạn có mô-đun nhị phân sử dụng một trong các thư viện bị ảnh hưởng, bạn phải cung cấp tệp .xcprivacy cho thư viện đó. OpenSSL là một thư viện bị ảnh hưởng bởi yêu cầu này, nhưng vẫn còn những thư viện khác.
Nếu bạn tạo một mô-đun nhị phân có tên mymodule.so và sử dụng tập lệnh xây dựng Xcode được mô tả ở bước 7 ở trên, thì bạn có thể đặt tệp mymodule.xcprivacy bên cạnh mymodule.so và bảng kê khai quyền riêng tư sẽ được cài đặt vào vị trí bắt buộc khi mô-đun nhị phân được chuyển đổi thành một khung.