移动应用开发:如何创建自定义Android代码模板

介绍

这篇教程会为你展示如何创建属于你自己的代码模板。大多数的Android开发者都至少一次使用过Android代码模板来新建工程。但是你有没有尝试过创建自己的Android代码模板?
在这篇教程中,我们将会为你展示可用于从Android Studio IDE生成包含Google Analytics配置的Android工程模板。

源码

这里下载源码

代码生成过程图解

具体创建步骤

要创建自己的模板,请确保:

  1. 你已经了解上述代码生成过程图解;
  2. 你有一些关于FreeMarker的知识;
  3. 你有一些关于Android IDE模板格式的知识,你可以在这里查看相关文档。

第一步:创建Google Analytics应用程序文件夹

这是你的模板目录,在Windows上,${android studio 安装路径}/plugins/android/lib/templates/,其他平台Linux,Mac OS请自行查找;
在GoogleAnalyticApplication文件夹中创建根文件夹和其他文件,如下所示:


第二步:创建template.xml文件

每个模板目录必须包含一个template.xml文件,这其中包含有关模板的一些元数据,包括名称,描述,类别和用户可见参数这些IDE将作为选项呈现给用户。
文件中还会在指明FreeMarker处理的recipe文件名称和全局变量文件,如果除了模板参数值之外还有全局变量应该对所有FreeMarker处理的文件可见。
Template.xml

<?xml version="1.0"?>
<template
    format="3"
    revision="4"
    name="Google Analytics Application"
    minApi="7"
    minBuildApi="14"
    description="Creates a new application that has already Google Analytics configuration.">
    <category value="Activity" />
    <formfactor value="Mobile" />
    <parameter
        id="activityClass"
        name="Activity Name"
        type="string"
        constraints="class|unique|nonempty"
        suggest="${layoutToActivity(layoutName)}"
        default="MainActivity"
        help="The name of the activity class to create" />
    <parameter
        id="layoutName"
        name="Layout Name"
        type="string"
        constraints="layout|unique|nonempty"
        suggest="${activityToLayout(activityClass)}"
        default="activity_main"
        help="The name of the layout to create for the activity" />
    <parameter
        id="classApplication"
        name="Class extends Application"
        type="string"
        constraints="nonempty|class"
        help="The name of class that extends from Application" />
    <parameter
        constraints="nonempty|string"
        id="googleAnalyticID"
        name="Google Analytic ID"
        type="string"
        help="Id of Google Analytic" />
    <parameter
        id="dispatchPeriod"
        name="Dispatch Period"
        help="Frequency of automatic dispatch in seconds. Defaults to 30 minutes (1800 seconds)."
        type="string"
        default="1800"/>
    <parameter
        id="autoActivityTracking"
        name="Auto Activity Tracking"
        help="If true, views (Activities) will be tracked automatically. false by default."
        type="boolean"
        default="false"/>
    <!-- 128x128 thumbnails relative to template.xml -->
    <thumbs>
        <!-- default thumbnail is required -->
        <thumb>template_google_analytics.png</thumb>
    </thumbs>
    <globals file="globals.xml.ftl" />
    <execute file="recipe.xml.ftl" />
 
</template>

其中的一些参数比如: activityClass, layoutName, classApplication, googleAnalyticID, dispatchPeriod, autoActivityTracking,将在创建项目时显示在弹出窗口中。

第三步:创建globals.xml.ftl文件

这是一个可选的文件,里面包含全局变量的定义,用于此模板的所有FreeMarker处理任务。
globals.xml.ftl

<?xml version="1.0"?>
<globals>
    <global id="manifestOut" value="${manifestDir}" />    
    <global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" />
    <global id="resOut" value="${resDir}" />    
</globals>

第四步:在root文件夹中创建相关文件和文件夹

root文件夹中包含模板源代码

1.创建AndroidManifest.xml.ftl
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="${packageName}">
    <application
        android:name="${packageName}.${classApplication}"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.gms.analytics.globalConfigResource"
            android:resource="@xml/analytics_global_config" />
        <activity
            android:name=".activities.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

其中的packageName,classApplication是在template.xml文件中定义的。

2.创建Application.java.ftl文件
package ${packageName};
import android.app.Application;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.Tracker;
/**
 * Created by TungDX on 5/29/2015.
 */
public class ${classApplication} extends Application {
    private static GoogleAnalytics analytics;
    private static Tracker tracker;
    @Override
    public void onCreate() {
       analytics = GoogleAnalytics.getInstance(this);
       tracker = analytics.newTracker("${googleAnalyticID}");
    }
    public static GoogleAnalytics getGoogleAnalytics() {
       return analytics;
    }
    public static Tracker getTracker() {
        return tracker;
    }
}

其中的packageName,googleAnalyticID是在template.xml文件中定义的。

3.创建MainActivity.java.ftl文件
package ${packageName}.activities;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import ${packageName}.${classApplication};
import ${packageName}.R;
public class MainActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onStart() {
        super.onStart();
        ${classApplication}.getGoogleAnalytics().reportActivityStart(this);
    }
    @Override
    protected void onStop() {
        super.onStop();
        ${classApplication}.getGoogleAnalytics().reportActivityStop(this);
    }
}

其中的packageName,classApplication是在template.xml文件中定义的。

4.创建activity_main.xml.ftl文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin">
    <TextView
        android:text="@string/ready"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>
5.创建strings.xml.ftl文件
<resources>
    <#if !isNewProject>
    <string name="title_${activityToLayout(activityClass)}">${escapeXmlString(activityTitle)}</string>
    </#if>
    <string name="ready">Google Analytic is ready!</string>
</resources>
6.创建dimens.xml文件
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
7.创建recipe.xml.ftl文件

recipe.xml文件中包含了从该模板生成代码时应执行的各个命令。比如,你可以复制某些文件或目录,或者通过FreeMarker运行源文件,并要求IDE在代码生成后打开一个文件。

<?xml version="1.0"?>
<recipe>
<dependency mavenUrl="com.android.support:support-v4:${targetApi}.+" />
<dependency mavenUrl="com.android.support:appcompat-v7:${targetApi}.+"/>
<dependency mavenUrl="com.google.android.gms:play-services:6+" />

<instantiate from="AndroidManifest.xml.ftl"to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />

<instantiate from="src/app_package/Application.java.ftl" to="${escapeXmlAttribute(srcOut)}/${classApplication}.java"/>

<instantiate from="src/app_package/activities/MainActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java"/>
 
<instantiate from="res/xml/analytics_global_config.xml.ftl" to="${escapeXmlAttribute(resOut)}/xml/analytics_global_config.xml"/>

<instantiate from="res/layout/activity_main.xml.ftl" to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml"/>

<copy from="res/values/dimens.xml" to="${escapeXmlAttribute(resOut)}/values/dimens.xml"/>

    <merge from="res/values/strings.xml.ftl"to="${escapeXmlAttribute(resOut)}/values/strings.xml" />   
    <open file="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java" />
    <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
</recipe>
8.检查依赖
9.检查AndroidManifest.xml.ftl
<instantiate from="AndroidManifest.xml.ftl"          to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />
10.检查Application.java.ftl
<instantiate from="src/app_package/Application.java.ftl" to="${escapeXmlAttribute(srcOut)}/${classApplication}.java"/>https://robusttechhouse.com/wp-admin/post.php?post=6937&action=edit&message=10#
11.检查MainActivity.java.ftl
<instantiate from="src/app_package/activities/MainActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java"/>

12.检查analytics_global_config.xml.ftl
<instantiate from="res/xml/analytics_global_config.xml.ftl" to="${escapeXmlAttribute(resOut)}/xml/analytics_global_config.xml"/>
13.从模板中生成 activity_main.xml, dimens.xml, strings.xml文件
<instantiate from="res/layout/activity_main.xml.ftl" to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml"/>
<copy from="res/values/dimens.xml" to="${escapeXmlAttribute(resOut)}/values/dimens.xml"/>
<merge from="res/values/strings.xml.ftl" to="${escapeXmlAttribute(resOut)}/values/strings.xml" />
14.工程创建成功后打开对应文件
<open file="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java" />
<open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />

如果你的Android Studio IDE运行,请重新启动它看到自己的模板如下图



如果从模板生成项目时遇到此错误:AssertionError: Wrong line separators: ‘…plication;\r\n\r\nimport…’ at offset 29:
请检查模板中所有文件的行分隔符是否正确,请确保使用正确的行分隔符在对应的的计算机的操作系统中。

原文链接

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

推荐阅读更多精彩内容