自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

創(chuàng)建和發(fā)布Android開發(fā)庫的終極指南

移動(dòng)開發(fā) Android
我經(jīng)常被 android 開發(fā)社區(qū)中如此多而且好用的第三方庫所震驚。有很長的一段時(shí)間,我想貢獻(xiàn)一些東西,但我不知道如何去做。在瀏覽了其他很多關(guān)于如何發(fā)布一個(gè) android 開發(fā)庫的文章后,我仍然發(fā)現(xiàn)缺失了一些細(xì)節(jié),而且,所有的信息都是在不同的地方。所以,我將完整的走過這個(gè)過程,向大家展示我的做法。

我經(jīng)常被 android 開發(fā)社區(qū)中如此多而且好用的第三方庫所震驚。有很長的一段時(shí)間,我想貢獻(xiàn)一些東西,但我不知道如何去做。在瀏覽了其他很多關(guān)于如何發(fā)布一個(gè) android 開發(fā)庫的文章后,我仍然發(fā)現(xiàn)缺失了一些細(xì)節(jié),而且,所有的信息都是在不同的地方。所以,我將完整的走過這個(gè)過程,向大家展示我的做法。

對(duì)新手來說,我推薦使用 Android Studio 來創(chuàng)建所有的 Android 項(xiàng)目,Android Studio官方使用 Gradle 構(gòu)建系統(tǒng)。請(qǐng)確保你下載了 Android Studio 的最新版。 

[[185318]] 

相關(guān)術(shù)語介紹

在我們開始之前,還有一些術(shù)語,需要熟悉下。

項(xiàng)目(Project) — 在 Android Studio 中,一個(gè) 項(xiàng)目 就是一個(gè)完整的 Android app。Android Studio 項(xiàng)目包含了一個(gè)或多個(gè)模塊。 在 Android Studio 中,一個(gè) 項(xiàng)目 類似于在 Eclipse 的一個(gè)工作區(qū)間( workspace )。

模塊( Module) – 一個(gè) 模塊 是 app 中的一個(gè)組件,它可以單獨(dú)的進(jìn)行構(gòu)建、測試和調(diào)試。模塊包含了 app 的源代碼和資源文件。在 Android Studio 中,一個(gè) 模塊 類似于在 Eclipse 的一個(gè)項(xiàng)目。

AAR – ‘aar’ 套件是 Android 開發(fā)庫項(xiàng)目的二進(jìn)制的分發(fā)形式。(AAR 格式)開發(fā)庫項(xiàng)目的主要產(chǎn)出就是 .aar 包(意思是 Android 壓縮包)。它是由編譯后的代碼(如 jar 文件或者 .so 文件)和資源文件(如 manifest 文件、res 文件、asset 文件)組合而成的。

Maven 中央倉庫 – 由 Maven 社區(qū)提供的倉庫。它包含了很多我們常用的開發(fā)庫。 Search Maven 網(wǎng)站可用來瀏覽 maven 中央倉庫的內(nèi)容。Gradle, Please 網(wǎng)站是另一個(gè)可用來搜索中央倉庫的工具。如果你在項(xiàng)目配置文件的倉庫配置部分添加了 jCenter() ,那么 Gradle 將使用 jCenter 倉庫( jCenter 的說明)。Maven 中央倉庫也經(jīng)常被稱作 Maven 中心或者中央倉庫。

Sonatype — Sonatype的開源軟件倉庫托管(OSSRH)服務(wù)是項(xiàng)目作者和貢獻(xiàn)者們發(fā)布他們的組件到中央倉庫的主要途徑。它是 Sonatype Nexus Professional 組織利用 Nexus Staging Suite 工具,對(duì)開源項(xiàng)目提供部署托管服務(wù),該服務(wù)主要用來處理部署和驗(yàn)證操作,也提供同步操作將內(nèi)容通過網(wǎng)絡(luò)投遞到中央倉庫。

GPG – GNU 隱私保護(hù)組織 (也稱為 GPG 或者 GnuPG),這個(gè) GNU 項(xiàng)目是一個(gè)加密軟件,遵循 OpenPGP (RFC4880)標(biāo)準(zhǔn),是 PGP 的免費(fèi)替代品。使用 GPG 你可以加密(解密)包含敏感數(shù)據(jù)的文件,比如那些由健康保險(xiǎn)攜帶和責(zé)任法案 (HIPAA) 制定的受保護(hù)的隱私和安全方面的電子健康信息。想了解 GPG 的更多信息,請(qǐng)?jiān)L問 GNU Privacy Guard website。

準(zhǔn)備好你的 Android 開發(fā)庫

我將使用我的 Trestle 開發(fā)庫作例子來講解。在你的項(xiàng)目中,需要修改一些地方,來準(zhǔn)備作為一個(gè)開發(fā)庫發(fā)布到 Maven 中央倉庫中。

  • 將開發(fā)庫的核心代碼和示例代碼區(qū)分開來。在我的項(xiàng)目中,我將他們分成 library 和 sample 兩個(gè)模塊。請(qǐng)仔細(xì)閱讀關(guān)于創(chuàng)建一個(gè)開發(fā)庫模塊的技巧。你也可能需要重命名你的模塊。
  • 在 sample 模塊的 build.gradle 文件中,請(qǐng)確保包含以下內(nèi)容:
  1. apply plugin: 'com.android.application' 
  2.  
  3. dependencies { 
  4.  
  5.     compile project(':library'
  6.  
  • 在 library 模塊的 build.gradle 文件中,請(qǐng)確保包含以下內(nèi)容:
  1. apply plugin: 'com.android.library' 
  2.  
  3. apply from'maven-push.gradle'  
  • 在 library 模塊中,增加 gradle.properties 文件,請(qǐng)確保在該文件中包含以下內(nèi)容:
  1. POM_NAME=ProjectName 
  2.  
  3. POM_ARTIFACT_ID=projectname 
  4.  
  5. POM_PACKAGING=aar  
  • 在 library 模塊中,增加 maven-push.gradle 文件,請(qǐng)確保在該文件中包含以下內(nèi)容:
  1. /* 
  2.  
  3. * Copyright 2013 Chris Banes 
  4.  
  5.  
  6. * Licensed under the Apache License, Version 2.0 (the "License"); 
  7.  
  8. * you may not use this file except in compliance with the License. 
  9.  
  10. * You may obtain a copy of the License at 
  11.  
  12.  
  13. *     http://www.apache.org/licenses/LICENSE-2.0 
  14.  
  15.  
  16. * Unless required by applicable law or agreed to in writing, software 
  17.  
  18. * distributed under the License is distributed on an "AS IS" BASIS, 
  19.  
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  21.  
  22. * See the License for the specific language governing permissions and 
  23.  
  24. * limitations under the License. 
  25.  
  26. */ 
  27.  
  28.   
  29.  
  30. apply plugin: 'maven' 
  31.  
  32. apply plugin: 'signing' 
  33.  
  34.   
  35.  
  36. def isReleaseBuild() { 
  37.  
  38.     return VERSION_NAME.contains("SNAPSHOT") == false 
  39.  
  40.  
  41.   
  42.  
  43. def getReleaseRepositoryUrl() { 
  44.  
  45.     return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 
  46.  
  47.             : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 
  48.  
  49.  
  50.   
  51.  
  52. def getSnapshotRepositoryUrl() { 
  53.  
  54.     return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 
  55.  
  56.             : "https://oss.sonatype.org/content/repositories/snapshots/" 
  57.  
  58.  
  59.   
  60.  
  61. def getRepositoryUsername() { 
  62.  
  63.     return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" 
  64.  
  65.  
  66.   
  67.  
  68. def getRepositoryPassword() { 
  69.  
  70.     return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" 
  71.  
  72.  
  73.   
  74.  
  75. afterEvaluate { project -> 
  76.  
  77.     uploadArchives { 
  78.  
  79.         repositories { 
  80.  
  81.             mavenDeployer { 
  82.  
  83.                 beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 
  84.  
  85.   
  86.  
  87.                 pom.groupId = GROUP 
  88.  
  89.                 pom.artifactId = POM_ARTIFACT_ID 
  90.  
  91.                 pom.version = VERSION_NAME 
  92.  
  93.   
  94.  
  95.                 repository(url: getReleaseRepositoryUrl()) { 
  96.  
  97.                     authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 
  98.  
  99.                 } 
  100.  
  101.                 snapshotRepository(url: getSnapshotRepositoryUrl()) { 
  102.  
  103.                     authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 
  104.  
  105.                 } 
  106.  
  107.   
  108.  
  109.                 pom.project { 
  110.  
  111.                     name POM_NAME 
  112.  
  113.                     packaging POM_PACKAGING 
  114.  
  115.                     description POM_DESCRIPTION 
  116.  
  117.                     url POM_URL 
  118.  
  119.   
  120.  
  121.                     scm { 
  122.  
  123.                         url POM_SCM_URL 
  124.  
  125.                         connection POM_SCM_CONNECTION 
  126.  
  127.                         developerConnection POM_SCM_DEV_CONNECTION 
  128.  
  129.                     } 
  130.  
  131.   
  132.  
  133.                     licenses { 
  134.  
  135.                         license { 
  136.  
  137.                             name POM_LICENCE_NAME 
  138.  
  139.                             url POM_LICENCE_URL 
  140.  
  141.                             distribution POM_LICENCE_DIST 
  142.  
  143.                         } 
  144.  
  145.                     } 
  146.  
  147.   
  148.  
  149.                     developers { 
  150.  
  151.                         developer { 
  152.  
  153.                             id POM_DEVELOPER_ID 
  154.  
  155.                             name POM_DEVELOPER_NAME 
  156.  
  157.                         } 
  158.  
  159.                     } 
  160.  
  161.                 } 
  162.  
  163.             } 
  164.  
  165.         } 
  166.  
  167.     } 
  168.  
  169.   
  170.  
  171.     signing { 
  172.  
  173.         required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } 
  174.  
  175.         sign configurations.archives 
  176.  
  177.     } 
  178.  
  179.   
  180.  
  181.     //task androidJavadocs(type: Javadoc) { 
  182.  
  183.     //source = android.sourceSets.main.allJava 
  184.  
  185.     //} 
  186.  
  187.   
  188.  
  189.     //task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 
  190.  
  191.     //classifier = 'javadoc' 
  192.  
  193.     //from androidJavadocs.destinationDir 
  194.  
  195.     //} 
  196.  
  197.   
  198.  
  199.     task androidSourcesJar(type: Jar) { 
  200.  
  201.         classifier = 'sources' 
  202.  
  203.         from android.sourceSets.main.java.sourceFiles 
  204.  
  205.     } 
  206.  
  207.   
  208.  
  209.     artifacts { 
  210.  
  211.         archives androidSourcesJar 
  212.  
  213.     } 
  214.  
  215.  
  • 修改在項(xiàng)目根目錄的 .gitignore 文件
  1. # [Android] ======================== 
  2.  
  3. # Built application files 
  4.  
  5. *.apk 
  6.  
  7. *.ap_ 
  8.  
  9.   
  10.  
  11. # Files for the Dalvik VM 
  12.  
  13. *.dex 
  14.  
  15.   
  16.  
  17. # Java class files 
  18.  
  19. *.class 
  20.  
  21.   
  22.  
  23. # Generated files 
  24.  
  25. bin/ 
  26.  
  27. gen/ 
  28.  
  29.   
  30.  
  31. # Gradle files 
  32.  
  33. .gradle/ 
  34.  
  35. build/ 
  36.  
  37.   
  38.  
  39. Local configuration file (sdk path, etc) 
  40.  
  41. local.properties 
  42.  
  43.   
  44.  
  45. # Proguard folder generated by Eclipse 
  46.  
  47. proguard/ 
  48.  
  49.   
  50.  
  51. # Log Files 
  52.  
  53. *.log 
  54.  
  55.   
  56.  
  57. ## Directory-based project format: 
  58.  
  59. .idea/ 
  60.  
  61.   
  62.  
  63. ## File-based project format: 
  64.  
  65. *.ipr 
  66.  
  67. *.iws 
  68.  
  69.   
  70.  
  71. ## Plugin-specific files: 
  72.  
  73.   
  74.  
  75. # IntelliJ 
  76.  
  77. out
  78.  
  79.   
  80.  
  81. # mpeltonen/sbt-idea plugin 
  82.  
  83. .idea_modules/ 
  84.  
  85.   
  86.  
  87. # JIRA plugin 
  88.  
  89. atlassian-ide-plugin.xml 
  90.  
  91.   
  92.  
  93. # Crashlytics plugin (for Android Studio and IntelliJ) 
  94.  
  95. com_crashlytics_export_strings.xml 
  96.  
  97.   
  98.  
  99. # [Maven] ======================== 
  100.  
  101. target/ 
  102.  
  103. pom.xml.tag 
  104.  
  105. pom.xml.releaseBackup 
  106.  
  107. pom.xml.versionsBackup 
  108.  
  109. pom.xml.next 
  110.  
  111. release.properties 
  112.  
  113.   
  114.  
  115. # [Gradle-Android] ======================== 
  116.  
  117.   
  118.  
  119. Ignore Gradle GUI config 
  120.  
  121. gradle-app.setting 
  122.  
  123.   
  124.  
  125. # Gradle Signing 
  126.  
  127. signing.properties 
  128.  
  129. trestle.keystore 
  130.  
  131.   
  132.  
  133. # Mobile Tools for Java (J2ME) 
  134.  
  135. .mtj.tmp/ 
  136.  
  137.   
  138.  
  139. # Package Files # 
  140.  
  141. *.jar 
  142.  
  143. *.war 
  144.  
  145. *.ear 
  146.  
  147.   
  148.  
  149. # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 
  150.  
  151. hs_err_pid* 
  152.  
  153.   
  154.  
  155. # Misc 
  156.  
  157. /.idea/workspace.xml 
  158.  
  159. .DS_Store 
  160.  
  161. /captures 
  162.  
  163. **/*.iml 
  164.  
  165. *.class  
  • 修改在項(xiàng)目根目錄的 settings.gradle 文件
  1. include ':sample'':library' 
  • 修改在項(xiàng)目根目錄的 gradle.properties 文件
  1. # Project-wide Gradle settings. 
  2.  
  3.   
  4.  
  5. # IDE (e.g. Android Studio) users: 
  6.  
  7. # Gradle settings configured through the IDE *will override* 
  8.  
  9. any settings specified in this file. 
  10.  
  11.   
  12.  
  13. For more details on how to configure your build environment visit 
  14.  
  15. # http://www.gradle.org/docs/current/userguide/build_environment.html 
  16.  
  17.   
  18.  
  19. # Specifies the JVM arguments used for the daemon process. 
  20.  
  21. # The setting is particularly useful for tweaking memory settings. 
  22.  
  23. Default value: -Xmx10248m -XX:MaxPermSize=256m 
  24.  
  25. # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 
  26.  
  27.   
  28.  
  29. When configured, Gradle will run in incubating parallel mode. 
  30.  
  31. # This option should only be used with decoupled projects. More details, visit 
  32.  
  33. # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 
  34.  
  35. # org.gradle.parallel=true 
  36.  
  37.   
  38.  
  39. VERSION_NAME=0.0.1 
  40.  
  41. VERSION_CODE=1 
  42.  
  43. GROUP=com.github.github_username 
  44.  
  45.   
  46.  
  47. POM_DESCRIPTION=A library that does X, Y, and Z 
  48.  
  49. POM_URL=https://github.com/github_username/ProjectName 
  50.  
  51. POM_SCM_URL=https://github.com/github_username/ProjectName 
  52.  
  53. POM_SCM_CONNECTION=scm:git@github.com:github_username/ProjectName.git 
  54.  
  55. POM_SCM_DEV_CONNECTION=scm:git@github.com:github_username/ProjectName.git 
  56.  
  57. POM_LICENCE_NAME=The Apache Software License, Version 2.0 
  58.  
  59. POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 
  60.  
  61. POM_LICENCE_DIST=repo 
  62.  
  63. POM_DEVELOPER_ID=github_username 
  64.  
  65. POM_DEVELOPER_NAME=GitHub FullName  
  • 增加 README.md 文件,向其他開發(fā)者介紹你的開發(fā)庫以及如何使用它。如果你想在你的 README.md 文件中增加些截圖,我極力推薦一款叫做Screenr的app。

安裝 GPG

如果你的機(jī)器上還沒安裝 GPG,你需要下載安裝它。如果你是 MacOSX 系統(tǒng),安裝手冊(cè)在這里。

如果你從未使用過 GPG – 首先,請(qǐng)創(chuàng)建 GPG 密鑰:

  1. $ gpg --gen-key 

在你創(chuàng)建 GPG 密鑰的時(shí)候,如果你不確定該如何回答問題, 這篇指南(Creating an encryption key)可以幫上忙。

接下來,找到你的密鑰 ID:

  1. $ gpg --list-keys 

第一行像是 pub XXXXX/YYYYYYYY <日期>的。切記,’YYYYYYYY’ 部分,就是你的密鑰 ID。

現(xiàn)在,發(fā)布你的密鑰:

  1. $ gpg --keyserver hkp://keyserver.ubuntu.com --send-keys YYYYYYYY 
  2.  
  3. $ gpg --keyserver hkp://pgp.mit.edu --send-keys YYYYYYYY  

你當(dāng)然也可以使用其他密鑰服務(wù)器,你也可以通過如下命令確認(rèn)你的密鑰是否已經(jīng)發(fā)布:

  1. $ gpg --keyserver hkp://pgp.mit.edu --search-keys johndoe@example.com # 使用你的郵箱 

為了使你的開發(fā)庫在 Gradle, Please網(wǎng)站上列出(也為了其他人方便的引用你的開發(fā)庫),請(qǐng)上傳你的項(xiàng)目到 Maven Central。 最簡單的上傳項(xiàng)目的方法是使用 Sonatype。

Sonatype

  1. 在Sonatype 創(chuàng)建一個(gè) JIRA 帳號(hào)。
  2. 登錄成功后,創(chuàng)建一個(gè) new issue。   

 

我為我的 Trestle 項(xiàng)目創(chuàng)建了一個(gè) GitHub 倉庫。所以我在 new issue 上填寫的字段大概如此:

Group Id : com.github.<github_username>

Project URL : https://github.com/<github_username>/<project_name>

SCM url : https://github.com/<github_username>/<project_name>.git

Username : <sonatype_username>

Already Synced to Central : No

注意:我在你需要填寫的字段上增加了括號(hào)作為占位符。你需要將它們替換成合適的值。

當(dāng)你準(zhǔn)備提交 issue 的時(shí)候,issue 的細(xì)節(jié)應(yīng)該要和上面的截圖差不多。當(dāng)你提交完成后,Sonatype 將用 2 個(gè)工作日來處理你的 issue。接著,你將收到一份確認(rèn)郵件,告知你的配置已經(jīng)準(zhǔn)備好了,你可以發(fā)布你的開源庫了。

不要部署你的開源庫,直到你接收到一封表明你的票據(jù)已經(jīng) OK 了的郵件。 對(duì)新項(xiàng)目來說,一個(gè)通病就是過早的部署。這將會(huì)誤使你的構(gòu)件(artifacts)變成一個(gè)人人都能獲得的倉庫。

最后,如果你的組件已經(jīng)在中央倉庫中了,請(qǐng)?jiān)谀愕钠睋?jù)中添加以下信息,并參考這篇文章,如何遷移到 OSSRH。

修改你本機(jī)上的 ~/.gradle/gradle.properties 文件,包含以下內(nèi)容:

  1. NEXUS_USERNAME=sonatype_username 
  2.  
  3. NEXUS_PASSWORD=sonatype_password 
  4.  
  5. signing.keyId=gpg_key_id 
  6.  
  7. signing.password=gpg_password 
  8.  
  9. signing.secretKeyRingFile=/Users/username/.gnupg/secring.gpg 
  10.  
  11. org.gradle.daemon=true  

當(dāng)你發(fā)布開發(fā)庫的時(shí)候,身份認(rèn)證信息已經(jīng)在 gradle.properties 文件中提供了。請(qǐng)確保提供了正確的 nexus 用戶名和密碼(也就是 Sonatype 的用戶名和密碼),否則你將得到未授權(quán)的 401 錯(cuò)誤。

注意:如果你之前已經(jīng)發(fā)布過一個(gè)開發(fā)庫,那么你不需要在 JIRA(Sonatype) 上創(chuàng)建一個(gè)新的 issue。每個(gè)頂級(jí)的 groupId 對(duì)應(yīng)一個(gè) JIRA issue。你應(yīng)該已經(jīng)有了部署任何新構(gòu)件到你的 groupId 或者下屬 group 應(yīng)需要的所有權(quán)限。中央倉庫的同步操作遵循從上到下的過程,所以任何下屬組的發(fā)布版本都將會(huì)自動(dòng)同步。當(dāng)你發(fā)布新組件,你不需要告訴 Sonatype,因?yàn)楫?dāng)你進(jìn)行倉庫同步工作的時(shí)候,沒有什么需要 Sonatype 去配置或者檢查的, Sonatype 僅僅會(huì)在第一次進(jìn)行同步操作的時(shí)候,發(fā)布一條 twitter。

發(fā)布

一旦你準(zhǔn)備發(fā)布你的開發(fā)庫,在 Android Studio 中, 打開右側(cè)的 Gradle 視圖,在 Tasks > upload 下,點(diǎn)擊 uploadArchives,將會(huì)上傳你的開發(fā)庫到 Sonatype Staging Repositories。   

 

在 Sonatype Staging Repositories 網(wǎng)頁上,登陸你的 Sonatype 賬號(hào),查找你的 “staging” 開發(fā)庫,它應(yīng)該在列表的最后,選中它,并按下 “關(guān)閉” 按鈕。關(guān)閉一個(gè)開發(fā)庫實(shí)際上意味著你準(zhǔn)備發(fā)布它。如果關(guān)閉操作一切順利 – 你應(yīng)該會(huì)看到一個(gè)激活了的 ‘發(fā)布’ 按鈕。你可能需要刷新下頁面。請(qǐng)按下發(fā)布按鈕。請(qǐng)閱讀關(guān)于使用 Nexus 管理倉庫的幫助文檔。如果這是你發(fā)布的第一個(gè)開發(fā)庫,返回到 JIRA,在 JIRA 上發(fā)表一條你已經(jīng)改進(jìn)了你的開發(fā)庫的評(píng)論,如果不是第一個(gè),就沒必要告訴 Sonatype 你改進(jìn)了你的開發(fā)庫。然后,你應(yīng)該會(huì)收到來自 Sonatype 的一條回復(fù)信息,信息上說你的開發(fā)庫在 10 分鐘內(nèi)能準(zhǔn)備好,將會(huì)在接下來的幾個(gè)小時(shí)同步到 Maven 中央倉庫。幾個(gè)小時(shí)之后,它將展示在 Gradle, Please 網(wǎng)站上。

使用你的開發(fā)庫

對(duì)其他開發(fā)者來說,想要使用你的開發(fā)庫,他們需要在 Android 項(xiàng)目的 build.gradle 文件中添加一條依賴, 如下所示:

  1. apply plugin: 'android' 
  2.  
  3. dependencies { 
  4.  
  5.     compile 'com.github.lawloretienne:trestle:0.0.3' 
  6.  

特別感謝

非常感謝 Chris Banes,Jonathan Le,Serge Zaitsev 以及其他發(fā)表博客的人們,你們的文章幫助我得以走過這個(gè)復(fù)雜的過程。

我的開發(fā)庫

QuickReturn — https://github.com/lawloretienne/QuickReturn

Trestle — https://github.com/lawloretienne/Trestle

ImageGallery — https://github.com/lawloretienne/ImageGallery 

責(zé)任編輯:龐桂玉 來源: 安卓開發(fā)精選
相關(guān)推薦

2009-03-06 10:11:30

2023-12-19 09:36:35

PostgreSQL數(shù)據(jù)庫開源

2024-01-17 08:00:56

LVM磁盤Linux

2023-05-05 17:20:04

2010-05-28 13:30:02

Visual Stud

2013-07-21 18:09:21

iOS開發(fā)ASIHttpRequ創(chuàng)建和執(zhí)行reques

2025-03-11 00:54:42

2012-08-21 06:53:00

測試軟件測試

2015-07-20 09:39:41

Java日志終極指南

2017-03-27 21:14:32

Linux日志指南

2020-07-19 08:15:41

PythonDebug

2009-05-19 15:01:26

地理信息ArcGIS地圖服務(wù)

2020-09-05 16:35:20

AndroidPython軟件開發(fā)

2025-04-21 03:30:00

2024-07-10 09:07:09

2023-05-23 18:31:14

Rust編程

2024-09-10 08:26:40

2022-06-30 08:00:00

MySQL關(guān)系數(shù)據(jù)庫開發(fā)

2024-08-19 00:40:00

SQL數(shù)據(jù)庫

2020-06-24 12:26:28

企業(yè)網(wǎng)絡(luò)IT管理
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)