Cách bắt đầu sử dụng mã C ++ trong dự án Android của bạn

Năm ngoái, tôi đã nói chuyện tại GDG DevFest ở Ankara, Thổ Nhĩ Kỳ. Tôi đã dự định chia sẻ bài nói chuyện đó ở đây kể từ đó. Bây giờ tôi là một ứng cử viên Tiến sĩ và có thêm một chút thời gian, tôi sẽ đưa bài viết xuống đây.

Nếu bạn muốn tải bản trình bày, nó có sẵn trên ổ của tôi.

Ấm lên

Tôi muốn bắt đầu bằng cách giải thích quá trình xây dựng một ứng dụng trong Android. Bởi vì bạn cần biết một số nội dung cơ bản, chủ đề này hơi mang tính kỹ thuật.

Bạn không cần biết mọi thứ được hiển thị trong hình trên - nhưng đó là một tài liệu tham khảo tốt.

Bây giờ giả sử rằng bạn viết một ứng dụng cho Android bằng Java. Bạn sẽ có:

  • mã nguồn cho ứng dụng đó
  • một số loại tệp tài nguyên (như hình ảnh hoặc tệp xml để sắp xếp GUI)
  • và có lẽ một số tệp AIDL, là các giao diện Java giúp các quy trình nói chuyện với nhau.

Có thể bạn cũng sẽ sử dụng các thư viện bổ sung và các tệp liên quan của chúng trong dự án của mình.

Khi xây dựng một ứng dụng hoạt động, trước tiên bạn phải biên dịch các mã nguồn đó lại với nhau. Một trình biên dịch sẽ mang lại một tệp DEX mà sau đó máy ảo có thể đọc được. Tệp mà máy có thể đọc được này và một số thông tin bổ sung về ứng dụng sẽ được đóng gói cùng nhau bởi trình quản lý gói. Gói cuối cùng - được gọi là gói APK - là ứng dụng cuối cùng.

Đây là quá trình xây dựng một gói Android theo cách đơn giản nhất.

Thời gian chạy Android

Bây giờ hãy nói về thời gian chạy. Bạn có một ứng dụng và khi nó bắt đầu chạy, nó sẽ được đọc bởi một máy. Android có hai loại máy ảo để chạy một ứng dụng. Tôi sẽ không giới thiệu cái cũ, được gọi là Dalvik, vì ngày nay hầu hết các thiết bị Android đều chạy một máy ảo có tên là Android Run Time, ART - vì vậy đó là những gì chúng ta sẽ nói ở đây.

ART là một máy ảo đi trước thời đại (AOT). Vậy điều đó có ý nghĩa gì? Hãy để tôi giải thích. Khi ứng dụng của bạn bắt đầu chạy lần đầu tiên, mã của ứng dụng được biên dịch thành mã máy, sau đó máy thật có thể đọc được. Điều này có nghĩa là mã không được biên dịch từng phần trong thời gian chạy. Điều này giúp tăng thời gian cài đặt ứng dụng đồng thời giảm mức sử dụng pin.

Tóm lại, bạn viết một ứng dụng sau đó biên dịch nó thành mã nhị phân được đọc bởi ART. Sau đó, ART chuyển đổi mã đó thành mã gốc mà thiết bị có thể đọc được.

NGHỆ THUẬT & C ++

Điều gì sẽ xảy ra nếu bạn viết ứng dụng Android bằng Java nhưng có một số mã C ++ tiếp xúc với Java? Ảnh hưởng của mã C ++ đó đối với quá trình xây dựng hoặc thời gian chạy ứng dụng của bạn là gì? Không quá nhiều.

Mã C ++ được trình biên dịch trực tiếp sang mã máy thực. Vì vậy, nếu bạn sử dụng mã C ++, nó sẽ được đóng gói dưới dạng mã máy đọc được trong gói của bạn. ART sẽ không xử lý lại nó trong khi nó chuyển đổi mã ART đọc được thành mã đọc được bằng máy ở lần sử dụng đầu tiên. Bạn không cần phải lo lắng về quá trình này. Bạn chỉ chịu trách nhiệm viết một giao diện cho phép Java nói chuyện với C ++. Chúng ta sẽ sớm nói về điều đó.

Quy trình xây dựng C ++

Bây giờ chúng ta phải nói về quá trình xây dựng C ++. Mã nguồn (các tệp .cpp và .h) được bộ xử lý tiền biến thành mã nguồn mở rộng trong bước đầu tiên. Mã nguồn này chứa rất nhiều mã. Mặc dù bạn có thể lấy tệp thực thi cuối cùng bằng cách sử dụng lệnh như trên, nhưng bạn có thể cắt các bước xây dựng với các cờ liên quan. Bạn có thể lấy mã nguồn mở rộng bằng cách đưa cờ -E cho trình biên dịch g ++ . Tôi có tệp dòng 40867 cho mã nguồn .cpp 4 dòng 'hello world'.

Sử dụng g ++ -E hello.cpp -o hello.ii để lấy mã nguồn mở rộng.

Bước thứ hai là bước biên dịch thực tế. Trình biên dịch biên dịch mã của chúng tôi để có được tệp trình hợp dịch. Vì vậy, quá trình biên dịch thực tạo ra một tệp hợp ngữ, không phải tệp thực thi. Tệp này được lắp ráp bởi một trình hợp dịch. Mã kết quả được gọi là mã đối tượng. Khi chúng ta có nhiều thư viện nhằm mục đích được liên kết với nhau, chúng ta có nhiều mã đối tượng. Các mã đối tượng đó được liên kết bởi một trình liên kết. Sau đó, chúng tôi nhận được một tệp thực thi.

Có hai loại liên kết: động và tĩnh.

Vì vậy, bây giờ đã đến lúc đi sâu hơn một chút khi chúng ta thảo luận về những thứ thuần túy C ++.

Điều quan trọng: Bạn có thể coi các thư viện được liên kết tĩnh như một phần của mã của bạn. Vì vậy, hãy cẩn thận khi bạn liên kết một thư viện với dự án của mình. Bởi vì thư viện bạn sử dụng có thể không có giấy phép phù hợp để được liên kết tĩnh. Hầu hết các thư viện nguồn mở đã bị hạn chế sử dụng dưới dạng liên kết động.

Từ quan điểm kỹ thuật, một thư viện được liên kết tĩnh được liên kết với dự án tại thời điểm xây dựng bởi trình biên dịch. Mặt khác, một thư viện liên kết động được liên kết bởi hệ điều hành tại thời điểm chạy. Vì vậy, bạn không cần phải phân phối dự án của mình với mã thư viện mà bạn sử dụng. Bạn cũng có thể sử dụng thư viện của dự án khác hoặc thư viện hệ thống.

Vì thực tế, liên kết động có thể gây ra lỗ hổng trong dự án của bạn. Tuy nhiên, trong khi trường hợp bảo mật nằm ngoài phạm vi của bài đăng này.

Một số khái niệm

CMake và Gradle

Nếu chúng ta muốn thêm mã C ++ vào dự án Android của mình, tốt hơn là sử dụng CMake để xử lý các hoạt động xây dựng. Bạn có nhớ quy trình xây dựng mà tôi vừa giới thiệu ở trên không? Khi bạn có một loạt các thư viện C ++ và mã nguồn, việc xử lý tất cả chúng trở nên phức tạp hơn. Một công cụ như CMake giúp thực hiện quá trình xây dựng dễ dàng hơn.

CMake sẽ có sẵn theo mặc định khi bạn chọn bao gồm hỗ trợ C ++ khi bắt đầu dự án của mình. Ngoài ra, bạn cần sử dụng bao đóng Gradle để đóng gói các thư viện vào APK của mình.

ABI

Như bạn đã biết, Android được phân phối cho nhiều loại thiết bị. Mỗi thiết bị có thể có một kiến ​​trúc CPU khác nhau. Khi bạn phát triển một ứng dụng Android có chứa mã C ++, bạn nên quan tâm đến nền tảng mà ứng dụng của bạn sẽ chạy.

Hãy nhớ cơ chế xây dựng C ++ mà tôi đã giới thiệu ở trên? Mã C ++ nên được biên dịch dưới dạng thư viện cho mỗi nền tảng bạn nhắm mục tiêu. Bạn có thể biên dịch thư viện cho tất cả các nền tảng được hỗ trợ hoặc bạn có thể chọn biên dịch nó chỉ cho một nền tảng.

Xin lưu ý rằng hỗ trợ ABI 64-bit sẽ là bắt buộc đối với bản phát hành Android Pie nếu bạn muốn đưa ứng dụng của mình vào Cửa hàng Google Play.

JNI

Đây là điều cuối cùng tôi muốn giới thiệu với bạn về việc sử dụng C ++ trong Android. Như tôi đã đề cập trước đây, tôi sẽ giới thiệu cho bạn những khái niệm này khi bạn muốn phát triển một ứng dụng bằng Java.

JNI là tên viết tắt của Java Native Interface. Nó cho phép các phần C ++ và Java nói chuyện với nhau bằng những thuật ngữ đơn giản nhất. Ví dụ, nếu bạn muốn gọi một hàm từ C ++ trong Java, bạn nên viết một giao diện JNI cho mục đích này.

Native-lib.cpp là giao diện và nó kết nối mã C ++ với mã Java. Trong ví dụ trên, mã C ++ duy nhất là chính JNI. Tuy nhiên, bạn có thể bao gồm các thư viện bạn muốn sử dụng và triển khai một hàm gọi chúng. Hàm mới này có thể được gọi từ phần Java. Vì vậy, nó hoạt động như một cầu nối theo cách đó.

Những điều cần làm trong trường hợp bạn muốn dùng thử

Tại đây, bạn có tất cả những kiến ​​thức cơ bản và cần thiết để sử dụng C ++ trong dự án Android của mình. Nếu bạn muốn thử, đây là cách tạo một dự án Android đơn giản với mã C ++.

Những hình ảnh dưới đây cho bạn thấy các bước để bắt đầu một dự án như vậy. Sau khi hoàn thành chúng, bạn có thể muốn đọc qua bài đăng này để sửa đổi và hiểu sâu hơn về cơ chế.

Bài đăng này chỉ là một phần giới thiệu. Đừng quên rằng có rất nhiều điều cần học hỏi. Tuy nhiên, tôi muốn giới thiệu cho bạn những điều quan trọng nhất về khái niệm sử dụng C ++.