如何在Android Studio中创建自定义项目模板
嘿,这个问题我太熟了!每次新项目都要手动加Hilt、Retrofit这些依赖、配置文件,确实烦到爆炸,自定义模板能省超多重复劳动。下面我一步步给你讲怎么弄,都是我自己实操过的靠谱步骤:
一、先找到Android Studio的模板目录
不同系统的模板根目录位置不一样,你对应找自己的:
- Windows:
C:\Program Files\Android\Android Studio\plugins\android\lib\templates\projects - Mac:
/Applications/Android Studio.app/Contents/plugins/android/lib/templates/projects - Linux:
/usr/local/android-studio/plugins/android/lib/templates/projects
你打开这个目录会看到自带的EmptyActivity、NavigationDrawerActivity这些模板,我们要在这里(或者用户自定义目录,后面会说)新建自己的模板文件夹,比如叫HiltRetrofitTemplate。
二、搭建自定义模板的核心结构
进入你新建的模板文件夹,需要这几个关键文件/文件夹,一个都不能少:
template.xml:模板的"身份证",告诉AS这个模板叫啥、要啥参数recipe.xml.ftl:模板生成的"执行逻辑",比如复制哪些文件、替换哪些变量globals.xml.ftl:定义模板里要用的全局变量root/:里面是你的项目模板代码(build.gradle、Activity、配置文件等,用变量占位符替换动态内容)template_blank.png:模板在AS创建界面的缩略图(可选,建议做个320x240的简单截图)
1. 编写template.xml(模板元数据)
这个文件是给AS看的配置,比如我们做带Hilt+Retrofit的模板,内容可以这样写:
<?xml version="1.0" encoding="UTF-8"?> <template name="Hilt + Retrofit 快速启动模板" description="预配置Hilt依赖注入、Retrofit网络请求的空项目" minApi="21" minBuildApi="30" category="Android" formFactor="Mobile"> <!-- 让用户输入的参数 --> <parameter id="appName" name="应用名称" type="string" constraints="nonempty" default="MyQuickApp" help="应用的显示名称"/> <parameter id="packageName" name="包名" type="string" constraints="package" default="com.example.myquickapp" help="应用的唯一包名"/> <!-- 缩略图配置 --> <thumbs> <thumb>template_blank.png</thumb> </thumbs> <!-- 关联其他配置文件 --> <globals file="globals.xml.ftl"/> <execute file="recipe.xml.ftl"/> </template>
2. 编写globals.xml.ftl(全局变量)
把需要在模板中重复使用的变量定义在这里,方便后续替换:
<?xml version="1.0" encoding="UTF-8"?> <globals> <global id="applicationPackage" value="${packageName}"/> <global id="appModuleName" value="app"/> <global id="androidXJetpack" value="true"/> </globals>
3. 填充root/文件夹的项目模板
这个文件夹就是你项目的"原型",所有动态内容用${变量名}替换。举几个关键文件的例子:
示例:root/app/build.gradle.kts(预配置依赖)
plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("com.google.dagger.hilt.android") kotlin("kapt") } android { namespace = "${applicationPackage}" compileSdk = 34 defaultConfig { applicationId = "${applicationPackage}" minSdk = 21 targetSdk = 34 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" } } dependencies { // 基础依赖 implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.11.0") // Hilt 依赖注入 implementation("com.google.dagger:hilt-android:2.48") kapt("com.google.dagger:hilt-android-compiler:2.48") // Retrofit + OkHttp implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:converter-gson:2.9.0") implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") } kapt { correctErrorTypes = true }
示例:root/app/src/main/java/${packageName}/MyApplication.kt(Hilt应用类)
package ${applicationPackage} import android.app.Application import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp class MyApplication : Application()
示例:root/app/src/main/AndroidManifest.xml(关联Hilt应用类)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="${applicationPackage}"> <application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.${appName}"> <activity android:name=".ui.MainActivity" android:exported="true" android:label="@string/app_name" android:theme="@style/Theme.${appName}.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
4. 编写recipe.xml.ftl(生成逻辑)
告诉AS如何处理你的模板文件:
<?xml version="1.0" encoding="UTF-8"?> <recipe> <!-- 复制app模块的所有文件到生成的项目 --> <copy from="root/app" to="${escapeXmlAttribute(projectOut)}/app" /> <!-- 复制项目根目录的gradle配置 --> <copy from="root/gradle.properties" to="${escapeXmlAttribute(projectOut)}/gradle.properties" /> <copy from="root/settings.gradle.kts" to="${escapeXmlAttribute(projectOut)}/settings.gradle.kts" /> <!-- 生成项目后自动打开AppModule,方便用户修改BaseUrl --> <open file="${escapeXmlAttribute(projectOut)}/app/src/main/java/${packageName}/di/AppModule.kt" /> </recipe>
三、测试自定义模板
做完所有步骤后,重启Android Studio,点击「New Project」,就能在模板列表里看到你刚创建的模板了!选它输入参数,生成的项目直接自带Hilt、Retrofit的全套配置,不用再手动折腾。
实用小技巧
安全备份模板:怕修改AS自带目录出问题?可以把模板放在用户自定义目录(不存在就自己建),重装AS也不会丢:
- Windows:
C:\Users\<你的用户名>\.android\templates\projects - Mac:
~/Library/Android/sdk/templates/projects - Linux:
~/.android/templates/projects
- Windows:
动态参数扩展:比如想让用户输入Retrofit的BaseUrl,只需要在
template.xml加个参数:<parameter id="baseUrl" name="Retrofit Base URL" type="string" constraints="nonempty" default="https://api.example.com/" help="网络请求的基础地址"/>然后在
globals.xml.ftl加<global id="baseUrl" value="${baseUrl}"/>,最后在AppModule.kt里用${baseUrl}替换硬编码的地址就行。排坑提示:如果AS识别不到模板,先检查文件夹结构是不是和自带模板一致,变量名有没有写错,或者文件路径里有没有中文/特殊字符。要是替换失败,打开生成的文件看看是不是
${变量名}没被正确替换,大概率是变量没在globals里定义。
要是中间哪个步骤卡壳了,随时喊我!我之前踩过不少坑,比如误删自带模板文件、变量名大小写错误这些,都能帮你排查~ 😎




