Computer >> Hướng Dẫn Máy Tính >  >> Hệ Thống >> Android

Làm chủ các dự án Android đa thư viện:Các phương pháp hay nhất để phát triển cục bộ và từ xa

Làm chủ các dự án Android đa thư viện:Các phương pháp hay nhất để phát triển cục bộ và từ xa

Trong bài viết này, chúng ta sẽ nói về các dự án đa thư viện trong Android. Đó không phải là điều gì đó bình thường nhưng cũng không phải là điều gì đó khác thường.

Bạn có thể đã gặp các dự án nhiều thư viện trong công việc của mình hoặc bạn có thể đang xem xét chuyển đổi thư viện của mình thành các mô-đun phụ để có cấu trúc và tổ chức tốt hơn. Dù thế nào đi nữa, bạn cũng nên nhận thức rõ những gì đang ở trước mặt mình trước khi lao vào.

Viết thư viện của riêng bạn trong Android thật gọn gàng. Bạn có cơ hội viết một số mã có thể giúp đỡ các nhà phát triển khác (hoặc thậm chí là chính bạn).

Vì các thư viện không thể tự mình là một dự án độc lập nên chúng thường luôn được ghép nối trong một dự án với một ứng dụng. Điều này cho phép phát triển thư viện thành một quy trình đơn giản trong đó bạn thêm một tính năng/sửa lỗi và sau đó bạn có thể kiểm tra nó trực tiếp bằng ứng dụng bạn có trong dự án. Do đó, mô phỏng (theo cách cục bộ) cách nhà phát triển sẽ tích hợp thư viện của bạn.

Tuy nhiên, điều gì sẽ xảy ra nếu thư viện của bạn dựa trên một thư viện khác mà bạn đang phát triển?

Nếu bạn không biết về nó, bạn nên biết rằng một thư viện (đọc aar) không thể chứa một thư viện cục bộ khác trong đó. Nó có thể dựa vào các thư viện từ xa (thông qua các phần phụ thuộc), nhưng không dựa vào thứ gì đó cục bộ.

Điều này không được hỗ trợ trong Android và mặc dù một số giải pháp đã xuất hiện trong nhiều năm (FatAar), nhưng những giải pháp này không phải lúc nào cũng giải quyết được vấn đề và không cập nhật. Thậm chí còn có Trình theo dõi sự cố của Google yêu cầu tính năng này đã được mở khá lâu và đang nhận được nhiều sự chú ý từ cộng đồng. Nhưng hãy xác định những bức tường nào chúng ta có thể phá vỡ và bức tường nào chúng ta không thể.

Hãy tưởng tượng hệ thống phân cấp dự án của bạn trông như thế này:

-- App
|
 -- OuterLib
 |
 --- InnerLib

Vì vậy, vì InnerLib không thể là một phần của dự án ban đầu của bạn nên nó có thể nằm ở đâu? Và làm cách nào bạn có thể làm việc cục bộ trong khi phát triển các tính năng bên trong InnerLib?

Chúng tôi sẽ trả lời những câu hỏi này trong bài viết này.

Mô-đun con Git

Đối với hầu hết các vấn đề kỹ thuật, không phải lúc nào cũng chỉ có một giải pháp. Thông thường, có nhiều hơn, nhưng mỗi giải pháp đều có nhược điểm. Vấn đề là bạn cảm thấy thoải mái hơn khi đối mặt với nhược điểm nào vào cuối ngày.

Để trả lời câu hỏi đầu tiên của chúng tôi, InnerLib có thể cư trú ở đâu, chúng tôi có một số lựa chọn:

  1. Biến InnerLib thành mô-đun con của dự án ban đầu của chúng tôi
  2. Biến InnerLib thành một phần phụ thuộc từ xa

Nếu bạn chưa biết về các mô-đun con trong Git, tài liệu của Git là nơi tốt để bạn làm quen với chúng. Trích dẫn từ đó (đoạn đầu tiên):

Điều thường xảy ra là khi làm việc trên một dự án, bạn cần sử dụng một dự án khác trong đó. 👉 Có thể đó là thư viện do bên thứ ba phát triển hoặc bạn đang phát triển riêng và sử dụng trong nhiều dự án mẹ. 👈 Một vấn đề phổ biến nảy sinh trong những trường hợp này:bạn muốn có thể coi hai dự án là riêng biệt nhưng vẫn có thể sử dụng một dự án từ bên trong dự án kia.

Đoạn này cho chúng ta thấy rằng đây chính xác là trường hợp sử dụng của chúng ta. Sử dụng một mô hình con có lợi ích của nó. Tất cả mã của bạn đều ở một nơi, dễ quản lý và dễ phát triển cục bộ.

Nhưng các mô-đun con có một số điểm yếu. Một là bạn phải luôn biết mô-đun con của bạn đang trỏ đến nhánh nào. Hãy tưởng tượng một tình huống trong đó bạn đang ở nhánh phát hành trong kho lưu trữ chính và mô-đun phụ của bạn nằm trên nhánh tính năng. Nếu bạn không để ý, bạn sẽ phát hành một phiên bản mã của mình với thứ gì đó chưa sẵn sàng để sản xuất. Rất tiếc.

Bây giờ hãy nghĩ về điều này trong một nhóm các nhà phát triển. Một sai lầm bất cẩn có thể phải trả giá đắt.

Nếu tùy chọn đầu tiên có vẻ khó khăn đối với bạn thì việc lưu trữ thư viện của bạn trong một kho lưu trữ khác là lựa chọn thứ hai. Việc thiết lập kho lưu trữ khá đơn giản, nhưng bây giờ bạn làm việc cục bộ như thế nào?

Làm việc tại địa phương

Bây giờ chúng ta đã thiết lập dự án của mình đúng cách, có thể chúng ta sẽ có một dòng tương tự như thế này trong tệp OuterLib build.gradle:

dependencies {
 implementation 'url_to_remote_inner_lib_repository'
}

Làm cách nào chúng ta có thể làm cho chu trình phát triển trở nên hiệu quả và dễ dàng làm việc? Nếu chúng tôi phát triển một số tính năng trong InnerLib thì làm cách nào để kiểm tra mọi thứ trong OuterLib? Hoặc trong ứng dụng của chúng tôi?

Một giải pháp có thể được đưa ra là nhập nội bộ InnerLib vào dự án OuterLib của chúng tôi, trong khi có InnerLib .gitignored trong dự án OuterLib của chúng tôi. Bạn có thể thực hiện việc này một cách dễ dàng bằng cách nhấp chuột phải vào tên dự án ở menu bên trái trong Android Studio và đi tới Mới → Mô-đun.

Làm chủ các dự án Android đa thư viện:Các phương pháp hay nhất để phát triển cục bộ và từ xa Cách nhập mô-đun (Bước 1)

Sau đó, trong cửa sổ mở ra, bạn có thể chọn tùy chọn Nhập ở dưới cùng bên trái:

Làm chủ các dự án Android đa thư viện:Các phương pháp hay nhất để phát triển cục bộ và từ xa Cách nhập mô-đun (Bước 2)

Điều đó nghe có vẻ dễ dàng và đơn giản cho đến nay, nhưng điều hấp dẫn là gì?

Mỗi lần bạn sửa đổi một tệp thuộc về InnerLib, những thay đổi đó sẽ không được phản ánh bên trong InnerLib vì nó bị bỏ qua. Vì vậy, mỗi thay đổi bạn muốn thực hiện phải diễn ra bên trong InnerLib và sau đó bạn phải nhập lại thay đổi đó vào OuterLib để xem các thay đổi.

Điều này có vẻ không đúng. Phải có cách tốt hơn để làm điều này.

Chỉ với một vài dòng trong settings.gradle của chúng tôi tệp, chúng tôi có thể đảm bảo các tệp của mình luôn được đồng bộ hóa khi chúng tôi thực hiện các thay đổi trong InnerLib.

Khi chúng tôi nhập InnerLib vào dự án của mình, Android Studio đã tạo một bản sao của InnerLib và lưu vào bộ nhớ đệm. Đó là lý do tại sao chúng tôi cần nhập lại thư viện cho mọi thay đổi mà chúng tôi đã thực hiện bên trong thư viện. Chúng tôi có thể cho Android Studio biết nơi tham chiếu các tệp bằng cách sử dụng projectDir thuộc tính.

settings.gradle của chúng tôi có thể trông giống như thế này:

include ':outerLib', ':innerLib', ':app'

Để tham chiếu InnerLib cục bộ, chúng ta sẽ phải thay đổi settings.gradle thành:

include ':outerLib', ':innerLib', ':app'
project('innerLib').projectDir = new File('PATH_TO_INNER_LIB')

Sử dụng phương pháp này, các tệp InnerLib của chúng tôi sẽ được liên kết với thư mục làm việc của chúng tôi, vì vậy mọi thay đổi chúng tôi thực hiện sẽ được phản ánh ngay lập tức.

Tuy nhiên, chúng tôi muốn có sự linh hoạt khi làm việc cục bộ trên OuterLib với phiên bản InnerLib từ xa. Những gì chúng tôi đã viết ở trên bên trong tệp settings.gradle sẽ chỉ cho phép chúng tôi làm việc cục bộ và chắc chắn chúng tôi không muốn cam kết điều đó như hiện tại.

Maven cục bộ

Nếu cách tiếp cận trên không phù hợp với bạn, bạn có thể thực hiện một cách khác. Giống như bạn xuất bản công khai thư viện của mình với maven, bạn có thể thực hiện điều tương tự cục bộ với maven local. Maven cục bộ là một tập hợp các kho lưu trữ cục bộ trên máy của bạn.

Dưới đây là các đường dẫn cho mavenLocal tùy thuộc vào hệ điều hành máy của bạn:

  • Mac → /Users/YOUR_USERNAME/.m2
  • Linux → /home/YOUR_USERNAME/.m2
  • Windows → C:\Users\YOUR_USERNAME.m2

Về bản chất, bạn có thể xuất bản thư viện của mình cục bộ và sau đó liên kết với nó trong dự án của bạn. Làm theo cách này, chúng ta có thể liên kết dự án của mình với InnerLib.

Để cho phép cấu hình này trong dự án của chúng tôi, chúng tôi cần thực hiện những việc sau:

  1. Thêm mavenLocal() như một kho lưu trữ bên trong mệnh đề kho lưu trữ của chúng tôi. Điều này cho phép dự án của chúng tôi có khả năng tìm kiếm các kho lưu trữ cục bộ
buildscript {
 repositories {
 mavenLocal()
 }
}
...
allprojects { 
 repositories { 
 mavenLocal() 
 }
}
  1. Thay đổi dòng triển khai bên trong mệnh đề phụ thuộc của chúng tôi để tham chiếu InnerLib như thể chúng tôi đang tham chiếu nó từ xa

  2. Để xuất bản InnerLib cục bộ, chúng tôi sẽ tạo một tệp có tên PublishLocally.gradle sẽ chứa những nội dung sau:

apply plugin: 'maven-publish' 
project.afterEvaluate {
 publishing { 
 publications {
 library(MavenPublication) { 
 setGroupId groupId //your library package
 setArtifactId artifactId 
 version versionName //I.E. 1.0
 artifact bundleDebugAar
 pom.withXml { 
 def dependenciesNode = asNode().appendNode('dependencies')
 def dependencyNode = dependenciesNode.appendNode('dependency')
 dependencyNode.appendNode('groupId', 'your_group_id')
 dependencyNode.appendNode('artifactId', 'your_artificat_id')
 dependencyNode.appendNode('version', 'your_version')
 } 
 }
 }
 }
}
  1. Bên trong tệp build.gradle cấp ứng dụng của bạn, hãy thêm dòng:
apply from: '/.publishingLocally.gradle

Nếu tùy chọn này có vẻ hơi quá tốt để có thể trở thành sự thật thì đúng là như vậy . Một mặt, chúng ta có thể phát triển mọi thứ cục bộ một cách liền mạch giống như thể chúng ta đang làm việc với một thư viện từ xa. Mặt khác, nếu chúng tôi thực hiện bất kỳ thay đổi nào bên trong InnerLib khi làm việc cục bộ, thì bắt buộc phải xuất bản lại nội bộ đó. Mặc dù đây không phải là một công việc tốn kém nhưng nó tạo ra nhu cầu phải thực hiện đi thực hiện lại những công việc tẻ nhạt.

Giải pháp làm việc cục bộ và từ xa

Chúng tôi muốn tránh việc phải liên tục xuất bản lại gói InnerLib bất cứ khi nào chúng tôi thực hiện thay đổi cục bộ. Chúng ta cần tìm ra cách để dự án của chúng ta nhận thức được những thay đổi đó.

Trong phần Làm việc cục bộ, chúng tôi đã tìm ra cách thực hiện điều đó nhưng chúng tôi gặp vấn đề với việc xác nhận tệp settings.gradle. Để giải quyết vấn đề này để chúng ta có thể làm việc cục bộ và từ xa với InnerLib, chúng ta sẽ sử dụng một tham số mà chúng ta sẽ xác định trong gradle.properties tập tin.

Tệp gradle.properties là nơi bạn có thể lưu trữ các cài đặt cấp dự án để định cấu hình môi trường phát triển của mình. Điều này giúp đảm bảo rằng tất cả các nhà phát triển trong nhóm đều có môi trường phát triển nhất quán.

Một số cài đặt bạn có thể quen thuộc được tìm thấy trong tệp này là hỗ trợ AndroidX (android.useAndroidX=true) hoặc các đối số JVM (org.gradle.jvmargs=-Xmx1536m).

Để giúp chúng tôi giải quyết tình huống của mình, chúng tôi có thể thêm một tham số vào đây để cho biết liệu chúng tôi có muốn làm việc tại địa phương hay không. Một cái gì đó tương tự như:

workingLocally = false

Tham số này sẽ cấp cho chúng tôi khả năng phân biệt giữa cài đặt nào chúng tôi đang làm việc, cục bộ hoặc bằng mã sản xuất. Trước tiên, hãy thay đổi những gì chúng ta có trong tệp settings.gradle bằng cách gói nó trong một điều kiện kiểm tra xem tham số của chúng ta có đúng hay không:

include ':outerLib', ':innerLib', ':app'
if (workingLocally.booleanValue()) {
 project('innerLib').projectDir = new File('PATH_TO_INNER_LIB')
}

Bằng cách này, chúng tôi chỉ định dự án để lấy các tệp cho InnerLib cục bộ từ máy của chúng tôi.

Một nơi khác mà chúng ta cần thay đổi logic là trong tệp build.gradle. Ở đây, thay vì lấy mã đến thư viện từ xa trong khối phụ thuộc, chúng tôi có thể cho biết liệu chúng tôi có phụ thuộc vào nó cục bộ hay không.

dependencies {
 if (workingLocally.booleanValue()) {
 implementation 'innerLib'
 } else {
 implementation 'url_to_remote_repository'
 }
}

⚠️ Lời cảnh báo:Bạn không bao giờ nên commit tệp gradle.properties khi làm việc cục bộ.

Cuộc hành trình kéo dài và có vẻ khá mệt mỏi. Nhưng giờ đây chúng tôi đã có thiết lập đầy đủ để làm việc cục bộ và từ xa trên một dự án nhiều thư viện.

Nếu bạn gặp phải bất kỳ vấn đề nào hoặc muốn đưa ra quan điểm về vấn đề này, vui lòng để lại nhận xét.

Học cách viết mã miễn phí. Chương trình giảng dạy mã nguồn mở của freeCodeCamp đã giúp hơn 40.000 người có được việc làm với tư cách là nhà phát triển. Bắt đầu