Everyone has talent. What is rare is the courage to follow the talent to the dark place where it leads.
人人都有天赋。罕见的是甘愿跟随天赋、尝尽人间甘苦的勇气。–艾瑞卡·容
android大致可以分为四层架构:Linux内核层,系统运行库层、应用框架层和应用层
Linux内核层
android系统是基于Linux内核,这一层为android设备的各种硬件提供了底层驱动。
系统运行库层
通过一些C/C++库来为android提供了主要的特性支持。还有android运行时库,主要提供一些库,允许开发者使用Java语言来编写android应用。
应用结构层
提供了构建应用程序时可能用到的各种API。
应用层
手机上的应用程序
Android 应用采用 Java 编程语言编写。Android SDK 工具将您的代码 — 连同任何数据和资源文件 — 编译到一个 APK:Android 软件包,即带有 .apk
后缀的存档文件中。一个 APK 文件包含 Android 应用的所有内容,它是基于 Android 系统的设备用来安装应用的文件。
安装到设备后,每个 Android 应用都运行在自己的安全沙箱内:
Android 系统可以通过这种方式实现最小权限原则。不过,应用仍可以通过一些途径来与其他应用共享数据及访问系统服务。
应用组件是 Android 应用的基本构建基块。共有四种不同的应用组件类型。每种类型都服务于不同的目的,并且具有定义组件的创建和销毁方式的不同生命周期。
Activity(活动)
Activity 表示具有用户界面的单一屏幕。凡是应用中看得到的都是放在活动中
Service(服务)
服务是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。 服务不提供用户界面。
Broadcast Receiver(广播接收器)
广播接收器是一种用于响应系统范围广播通知的组件。例如电话,短信等
Content Provider(内容提供器)
内容提供程序管理一组共享的应用数据,为应用程序之间数据共享提供了可能。
Android 系统设计的独特之处在于,任何应用都可以启动其他应用的组件。与大多数其他系统上的应用不同,Android 应用并没有单一入口点(例如,没有 main()
函数)。
四种组件类型中的三种 — Activity、服务和广播接收器 — 通过名为 Intent 的异步消息进行启动。
每种类型的组件有不同的启动方法:
Intent
传递到 startActivity()
或 startActivityForResult()
(当您想让 Activity 返回结果时)来启动 Activity(或为其安排新任务)。Intent
传递到 startService()
来启动服务(或对执行中的服务下达新指令)。 或者,您也可以通过将 Intent
传递到 bindService()
来绑定到该服务。Intent
传递到 sendBroadcast()
、sendOrderedBroadcast()
或 sendStickyBroadcast()
等方法来发起广播;ContentResolver
上调用 query()
来对内容提供程序执行查询。在 Android 系统启动应用组件之前,系统必须通过读取应用的 AndroidManifest.xml
文件(“清单”文件)确认组件存在。 您的应用必须在此文件中声明其所有组件,该文件必须位于应用项目目录的根目录中。
除了声明应用的组件外,清单文件还有许多其他作用,如:
声明组件
清单文件的主要任务是告知系统有关应用组件的信息。
声明组件功能
当您在应用的清单文件中声明 Activity 时,可以选择性地加入声明 Activity 功能的 Intent 过滤器,以便响应来自其他应用的 Intent。
声明应用要求
您必须通过在清单文件中声明设备和软件要求,为您的应用支持的设备类型明确定义一个配置文件。
Android 应用并非只包含代码 — 它还需要与源代码分离的资源,如图像、音频文件以及任何与应用的视觉呈现有关的内容。提供了丰富的系统控件爱你,SQLite数据库,强大的多媒体,地理位置定位等。
切换为project工程模式
.gradle
与.ideal
放置android studio自动生成的文件
app
存放项目中的代码,资源等内容
.gitignore
用来将指定的目录或文件排除在版本控制之外
build.gradle
项目全局gradle构建脚本
.gradel.properties
全局的gradle配置文件,其属性会影响到项目中所有的gradle编译脚本
.gradlew
和gradle.bat
用在命令行中执行gradle命令。前者linux或mac,后者windows
HelloWorld.iml
标识这是一个IntelliJ IDEA项目,无需修改
local.properties
指定本机中Android SDK路径。
settings.gradle
用于指定项目中所有引入的模块
详解res中的资源类型
注意:这么多mipmap文件夹是为了让程序更好的兼容各种设备,drawable也是,需要自己创建。
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {//这里是gradle脚本执行所需依赖,分别是对应的maven库和插件
repositories {
google()//从Android Studio3.0后新增了google()配置,可以引用google上的开源项目
jcenter()//是一个类似于github的代码托管仓库,声明了jcenter()配置,可以轻松引用 jcenter上的开源项目
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'此处是android的插件gradle,gradle是一个强大的项目构建工具
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {//这里是项目本身需要的依赖,比如项目所需的maven库
repositories {
google()
jcenter()
}
}
// 运行gradle clean时,执行此处定义的task任务。
// 该任务继承自Delete,删除根目录中的build目录。
// 相当于执行Delete.delete(rootProject.buildDir)。
// gradle使用groovy语言,调用method时可以不用加()。
task clean(type: Delete) {
delete rootProject.buildDir
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.baiheng.helloworld"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
这里我们分块解释:
apply plugin: 'com.android.application'
这里表示应用了一个插件,该插件有两种值可选:
'com.android.application' //表示该模块为应用程序模块,可以直接运行,打包得到的是.apk文件
'com.android.library' //表示该模块为库模块,只能作为代码库依附于别的应用程序模块来运行,打包得到的是.aar文件
这个闭包主要配置项目构建的各种属性:
可以往里面添加signingConfigs{}闭包
示例:
signingConfigs {// 自动化打包配置
release {// 线上环境
keyAlias 'test'
keyPassword '123456'
storeFile file('test.keystore')
storePassword '123456'
}
debug {// 开发环境
keyAlias 'test'
keyPassword '123456'
storeFile file('test.keystore')
storePassword '123456'
}
}
可以手动添加签名配置,也可以通过Project Structure 选中app,点击Singing添加,具体步骤如下图所示:
签名配置完成后可以方便带签名打包,在module的Build Variants中有两个Type,分别是debug和release,可以选择任意一个类型进行打包,并且他们会利用各自配置的Key进行打包,执行 Run app或者Build->Build apk就会自动在module name/app/build/outputs/apk路径下生成Apk文件。另一种打包方式是Build->Generate Signed APK填写签名信息生成Apk。
compileSdkVersion:设置编译时用的Android版本
buildToolsVersion:设置编译时使用的构建工具的版本
添加defaultConfig{}闭包
defaultConfig {
applicationId "com.baiheng.helloworld" //项目的包名
minSdkVersion 21 //项目最低兼容的版本
targetSdkVersion 29 //项目的目标版本
versionCode 1 //版本号
versionName "1.0" //版本名称
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" //表明要使用AndroidJUnitRunner进行单元测试
}
添加buildTypes{}闭包
这个闭包主要指定生成安装文件的主要配置,一般包含两个包,一个debug闭包和一个release闭包,分别指定生成测试版和正式版安装文件配置。
buildTypes {// 生产/测试环境配置
release {// 生产环境
buildConfigField("boolean", "LOG_DEBUG", "false")//配置Log日志
buildConfigField("String", "URL_PERFIX", "\"https://release.cn/\"")// 配置URL前缀
minifyEnabled false//是否对代码进行混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
signingConfig signingConfigs.release//设置签名信息
pseudoLocalesEnabled false//是否在APK中生成伪语言环境,帮助国际化的东西,一般使用的不多
zipAlignEnabled true//是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率
applicationIdSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
versionNameSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
}
debug {// 测试环境
buildConfigField("boolean", "LOG_DEBUG", "true")//配置Log日志
buildConfigField("String", "URL_PERFIX", "\"https://test.com/\"")// 配置URL前缀
minifyEnabled false//是否对代码进行混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
signingConfig signingConfigs.debug//设置签名信息
debuggable false//是否支持断点调试
jniDebuggable false//是否可以调试NDK代码
renderscriptDebuggable false//是否开启渲染脚本就是一些c写的渲染方法
zipAlignEnabled true//是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率
pseudoLocalesEnabled false//是否在APK中生成伪语言环境,帮助国际化的东西,一般使用的不多
applicationIdSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
versionNameSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
}
}
添加sourceSets{}闭包
sourceSets {//目录指向配置
main {
jniLibs.srcDirs = ['libs']//指定lib库目录
}
}
配置目录指向。配置 jniLibs.srcDirs = [‘libs’],可以在Android studio的Android视图下生成jniLibs文件夹,可以方便我们存放jar包和库文件,其中Android视图下的jniLibs和project视图下的libs指向同一文件夹(app→libs)
添加packagingOptions{}闭包
打包时的相关配置。项目依赖的第三方库较多时,两个依赖库存在同一个(名称)文件,这个Gradle打包会提示错误(警告),可根据提示使用如下方法将重复文件剔除。
packagingOptions{
//pickFirsts做用是 当有重复文件时 打包会报错 这样配置会使用第一个匹配的文件打包进入apk
// 表示当apk中有重复的META-INF目录下有重复的LICENSE文件时 只用第一个 这样打包就不会报错
pickFirsts = ['META-INF/LICENSE']
//merges何必 当出现重复文件时 合并重复的文件 然后打包入apk
//这个是有默认值得 merges = [] 这样会把默默认值去掉 所以我们用下面这种方式 在默认值后添加
merge 'META-INF/LICENSE'
//这个是在同时使用butterknife、dagger2做的一个处理。同理,遇到类似的问题,只要根据gradle的提示,做类似处理即可。
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
添加productFlavors{}闭包
多个渠道配置。通常在适配多个渠道时,需要为特定的渠道做部分特殊处理,比如设置不同的包名,应用名等。
android {
productFlavors {
wandoujia {
//豌豆荚渠道包配置
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
//manifestPlaceholders的使用在后续章节(AndroidManifest里的占位符)中介绍
}
xiaomi {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
applicationId "com.wiky.gradle.xiaomi" //配置包名
}
_360 {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
}
//...
}
}
添加lintOptions{}闭包
Lint 是Android Studio 提供的代码扫描分析工具,它可以帮助我们发现代码结构/质量问题,同时提供一些解决方案
//程序在编译的时候会检查lint,有任何错误提示会停止build,我们可以关闭这个开关
lintOptions {
abortOnError false //即使报错也不会停止打包
checkReleaseBuilds false //打包release版本的时候进行检测
}
dependencies{}闭包
该闭包定义了项目的依赖关系,一般项目都有三种依赖方式:本地依赖、库依赖和远程依赖。
本地依赖可以对本地的jar包或目录添加依赖关系,库依赖可以对项目中的库模块添加依赖关系,远程依赖可以对jcener库上的开源项目添加依赖关系。从Android Studio3.0后compile引入库不在使用,而是通过api和implementation,api完全等同于以前的compile,用api引入的库整个项目都可以使用,用implementation引入的库只有对应的Module能使用,其他Module不能使用
,由于之前的项目统一用compile依赖,导致的情况就是模块耦合性太高,不利于项目拆解,使用implementation之后虽然使用起来复杂了但是做到降低偶合兴提高安全性。
dependencies {//项目的依赖关系
implementation fileTree(include: ['*.jar'], dir: 'libs')//本地jar包依赖
implementation 'com.android.support:appcompat-v7:27.1.1'//远程依赖
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'//声明测试用例库
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
implementation fileTree(include: ['*.jar'], dir: 'libs')
是个本地依赖声明,表示将libs目录下所有.jar后缀的文件都添加到项目的构建路径当中。
日志工具中提供了5各方法来供打印日志:
Log.v()
:打印最为琐碎,意义最小的日志信息。对应级别verbose,级别最低Log.d()
:打印调试信息,对应级别为debug,比verbose高一级。Log.i()
:打印重要数据,分析用户行为数据,对应级别info,比debug高一级Log.w()
:打印一些警告信息,对应级别为warn,比info高一级Log.e()
:打印程序中错误信息,对应级别为error,最高级别打开命令行并切换当前目录到Andriod项目的根目录,在debug模式下使用Gradle编译项目,使用gradle脚本执行assembleDebug编译项目,执行后会在build/目录下生成XXX-debug.apk。
Window操作系统下,执行:
gradlew.bat assembleDebug
Mac OS或Linux系统下:
$ chmod +x gradlew
$ ./gradlew assembleDebug
编译完成后在app/build/outputs/apk/目录生成apk
Note: chmod命令是给gradlew增加执行权限,只需要执行一次。
确保 Android SDK里的 platform-tools/
路径已经添加到环境变量PATH
中,执行:
adb install XXX-debug.apk
//或者
adb install -r XXX-debug.apk
则成功将apk安装到Android设备中。