Android APP开发入门(2)——Android项目结构简介

项目结构
  • app:主要代码所在目录
    • build:编译打包时产生的临时文件,打包产物默认也在此目录中。上传git时,需隐忽略此文件夹
    • src:主要编写代码的地方
      • androidTest:android特有的单元测试
      • main:主要盛放源代码和资源文件
      • java.包名:java源代码,各种页面、控件、页面逻辑等在此文件下编写
      • res:资源文件,盛放了布局、控件样式、动画、图片、颜色、文本、主题等相关资源
        • drawable:控件背景,颜色,形状等
        • layout:布局文件
        • mipmap-xxx:不同分辨率的图片文件
        • values
          • colors.xml:颜色值,根据默认格式继续扩展即可
          • strings.xml:文本,根据默认格式继续扩展即可
          • theme.xml:主题
          • attrs.xml:自定义控件属性声明
          • style.xml:控件样式
          • dimens.xml:距离,控件大小单位,字体大小单位
      • AndroidManifest.xml:清单文件,主要用于权限的声明、四大组件注册、主题样式的引用、图标的配置、APP名称的配置等
    • test:基于JUnit的单元测试
    • .gitignore:git忽略文件
    • build.gradle:模块的配置文件,用于声明依赖,配置打包参数等等
    • proguard-rules.pro:混淆配置文件,当打开混淆功能时,用于配置哪些类、库等被混淆忽略
  • build.gradle:整个项目的配置文件,用于声明第三方依赖下载源,gradle插件引用,
  • gradle.properties:可用于声明gradle文件可直接引用的常量。默认声明了编译时jvm的内存大小和编码格式、使用androidX
  • gradlewgradlew.bat:运行gradle命令的脚本,无需配置gradle环境变量,直接使用gradlew,一般不要修改
  • local.properties:本地参数,git上传时需忽略
  • settings.gradle:项目配置文件,主要用来声明不同模块(module)

开始编码

很多时候,在开始新项目时,我们需要依赖很多库,并且根据这些库开发很多基本的工具。此时你可以新建一个module,用于编写基本的功能。当然也可以不用创建。

新建module

在android项目中,module主要分为两种,一种是application,一种是library,application的打包结果是apk,即可安装的文件。library的打包结果是aar,用于供其他application使用。
一个非组件化的项目中,一般只有一个application和n个library,默认新建的项目,app目录即为application的module。

步骤

新建module

右击根目录,选择New->Module
下一步

新建module和新建项目相似

新建完module后,你会发现,文件树中出现了一个文件夹,图标有些特殊。更改的地方还有settings.gradle文件,可打开观察不同
如果需要删除这个module,需先删除settings.gradle中的相应值,编译一下,然后右击文件树要删除的文件夹即可删除。

我们继续观察,从app目录下的文件和新建module_base目录下的内容相差无几,主要差距如下:

  • 包名不同
  • build.gradle第二行不同,一个是com.android.application,一个是com.android.library

此时两个module之间还没有任何联系,还处在你是你我是我的关系,但我们新建module_base的目的就是为了给app模块提供基本支持,所以我们要让app模块依赖module_base
在app模块中的build.gradle中添加如下内容

dependencies {
  //...
  implementation project(':module_base')
}

现在我们已经建了两个module,接下来就可以添加相关三方库依赖了。
在添加依赖前,先介绍两个关键字

  • implementation:添加的依赖,只能在本module中使用
  • api:添加的依赖,可公开给其他依赖本module的module使用。

所以,你可根据不同情况使用不同的关键词

添加三方依赖

一个常见的APP,要有网络请求的功能,要有图片显示的功能,还可能需要其他许许多多的功能,在这些常见且基础的功能中,有很多人为我们写好了优秀的代码库,我们可以直接拿来使用。
如何添加三方依赖呢,和module之间的依赖相同,直接在dependencies代码块中引用即可:

dependencies {
  //原有的引用,把implementation改为api,使其公开为其他module使用
  api 'androidx.core:core-ktx:1.3.2'
  api 'androidx.appcompat:appcompat:1.2.0'
  //原生控件库,materia风格库
  api 'com.google.android.material:material:1.3.0'
  //Compose相关依赖
  api "androidx.compose.ui:ui:$compose_version"
  api "androidx.compose.material:material:$compose_version"
  api "androidx.compose.ui:ui-tooling-preview:$compose_version"
  api 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
  api 'androidx.activity:activity-compose:1.3.0-alpha06'

  //约束布局库
  api 'androidx.constraintlayout:constraintlayout:2.0.4'
  //网络请求Retrofit库
  api 'com.squareup.retrofit2:retrofit:2.9.0'
  api 'com.squareup.retrofit2:converter-gson:2.9.0'
  //网络请求日志库
  api 'com.squareup.okhttp3:logging-interceptor:4.3.1'
  //图片请求库
  api 'com.github.bumptech.glide:glide:4.11.0'
  //测试相关库
  testImplementation 'junit:junit:4.+'
  androidTestImplementation 'androidx.test.ext:junit:1.1.2'
  androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

上面这些依赖,已基本满足一个APP的开发。
如果想查看库的最新版,可在
https://mvnrepository.com/
中查看相应的版本号。
当你添加完依赖后,记得同步一下项目;如果需要同步,右上角会出现Sync now按钮,如果不需要同步,则不会出现。

Gradle

Android项目的管理主要使用的是Gradle,因此需要了解一些Gradle相关知识。

Gradle是基于Groovy的特定领域语言,基于JVM。因此对于Java工程师来说入门相对容易一些。

有时AS无法下载Gradle或下载过慢,这个时候可以根据项目中的gradle/wrapper/gradle-wrapper.properties文件中的distributionUrl网址,去用浏览器或工具下载。然后把压缩包手动放到C:\Users\xxx\.gradle\wrapper\dists\gradle-x.x.x-xxx\xxxxxxxxxxxxx路径下即可(此路径会在第一次下载时自动创建),然后从新打开项目即可

我们先来认识一下Android项目中几个主要的gradle文件。

根目录build.gradle

// 顶级构建文件,您可以在其中添加所有子项目模块通用的配置选项。
buildscript {
    ext {
        //定义的常量,所有子项目中可以引用
        compose_version = '1.0.1'
    }
    //库下载源
    repositories {
        google()
        mavenCentral()
    }
    //gradle依赖的插件
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.2"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

//清理任务,运行后可清理所有build目录
task clean(type: Delete) {
    delete rootProject.buildDir
}

根目录settings.gradle

//所有module依赖的统一配置
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    //下载源
    repositories {
        google()
        mavenCentral()
        jcenter() // Warning: this repository is going to shut down soon
    }
}
//根项目名
rootProject.name = "LearnCompose"
//包含的module,也可这样声明include ':app', ':module_base'
include ':app'
include ':module_base'

module目录中build.gradle

//插件的引用
plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    //编译SDK版本号
    compileSdk 30

    defaultConfig {
        //包名
        applicationId "com.withme.learncompose"
        //最小支持的SDK
        minSdk 21
        //目标SDK
        targetSdk 30
        //APP版本号
        versionCode 1
        //APP版本名称
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        //开启矢量图支持
        vectorDrawables {
            useSupportLibrary true
        }
        //开启分包
        multiDexEnabled true
    }

    buildTypes {
        //正式版配置内容
        release {
            //最小化是否开启
            minifyEnabled false
            //指定混淆文件
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    //编译配置,开启java8支持
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    //kotlin配置,jvm目标版本1.8,开启JVM IR后端
    kotlinOptions {
        jvmTarget = '1.8'
        useIR = true
    }
    buildFeatures {
        //开启jetpack compose功能
        compose true
    }
    //compose配置
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
        kotlinCompilerVersion '1.5.21'
    }
    //打包配置
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
}
//依赖模块
dependencies {
    //声明依赖
    //从网络引用依赖
    //implementation  'androidx.core:core-ktx:1.3.2'
    //从本地引用依赖
    implementation project(':module_base')
}

自定义

1.添加构建类型

默认只有release和debug类型,且未开启混淆,如果想把release类型开启混淆,则:

//在android{}中
buildTypes {
    release {
        shrinkResources true
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

在AS左下角的BuildVariants中可以进行切换,切换后每次运行都会根据你选择的类型进行打包运行,开启混淆打包运行过程会超慢。

2.重命名打包apk的名称

默认的apk文件名,很简单app-构建类型.apk,有时想改变打包产物的文件名:

//还是在android{}中
//无多渠道版本,apk文件名为:app_构建类型_版本名称_版本号_当前日期.apk
android.applicationVariants.all {
    variant ->
        variant.outputs.all {
            output -> output.outputFileName = "app_" + buildType.name + "_v" + defaultConfig.versionName + "_"+ defaultConfig.versionCode + "_" + new Date().format("yyyyMMdd") + ".apk"
        }
}
//多渠道版本,apk文件名:构建渠道名_构建类型_渠道版本名称_渠道版本号_当前日期.apk
android.applicationVariants.all {
    variant ->
        variant.outputs.all {
            output -> output.outputFileName = variant.productFlavors[0].name+"_" + buildType.name + "_v" + variant.productFlavors[0].versionName + "_"+ variant.productFlavors[0].versionCode + "_" + new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC")) + ".apk"
        }
}

3.常量声明

有时想在build.gradle中希望声明一个常量,使其在代码中使用。可以使用如下方法:

buildTypes {
    release {
        shrinkResources true
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        buildConfigField "String","X_VALUE",'"你好哈"'
    }
    debug {
        buildConfigField "String","X_VALUE",'"Hello"'
    }
}

当进行了以上声明,在代码中可以直接使用BuildConfig.X_VALUE了。当然,你也可以声明其他基本数据类型。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容