diff --git a/Makefile.am b/Makefile.am
index 592e75a77..c0ccec411 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -285,7 +285,7 @@ libmain_a_CPPFLAGS = $(AM_CPPFLAGS) -Iandroid/build/include
 
 src_mpd_LDADD += libandroid.a libjava.a
 
-all-local: android/build/bin/$(APK_NAME)-debug.apk
+all-local: android/build/$(APK_NAME)-debug.apk
 clean-local:
 	rm -rf android/build
 
@@ -298,25 +298,49 @@ ANDROID_SDK_PLATFORM = android-17
 ANDROID_BUILD_TOOLS_DIR = $(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_VERSION)
 ANDROID_SDK_PLATFORM_DIR = $(ANDROID_SDK)/platforms/$(ANDROID_SDK_PLATFORM)
 
+JAVAC = javac
+AAPT = $(ANDROID_BUILD_TOOLS_DIR)/aapt
+DX = $(ANDROID_BUILD_TOOLS_DIR)/dx
 ZIPALIGN = $(ANDROID_BUILD_TOOLS_DIR)/zipalign
 
-android/build/build.xml: android/AndroidManifest.xml
-	rm -rf android/build
-	mkdir -p android/build/include android/build/res android/build/src/org
-	ln -s $(abs_srcdir)/android/AndroidManifest.xml $(abs_srcdir)/android/custom_rules.xml android/build
-	ln -s $(abs_srcdir)/android/src android/build/src/org/musicpd
-	ln -s $(abs_srcdir)/android/res/values $(abs_srcdir)/android/res/layout android/build/res
-	$(ANDROID_SDK)/tools/android update project --path android/build --target $(ANDROID_SDK_PLATFORM) --name $(APK_NAME)
+ANDROID_XML_RES := $(wildcard $(srcdir)/android/res/*/*.xml)
+ANDROID_XML_RES_COPIES := $(patsubst $(srcdir)/android/%,android/build/%,$(ANDROID_XML_RES))
 
-android/build/bin/classes/org/musicpd/Bridge.class: android/src/Bridge.java android/build/build.xml android/build/res/drawable/icon.png
-	cd android/build && ant compile-jni-classes
+JAVA_SOURCE_NAMES = Bridge.java Loader.java Main.java
+JAVA_SOURCES = $(addprefix $(srcdir)/android/src/,$(JAVA_SOURCE_NAMES))
 
-android/build/include/org_musicpd_Bridge.h: android/build/bin/classes/org/musicpd/Bridge.class
-	javah -classpath $(ANDROID_SDK_PLATFORM_DIR)/android.jar:android/build/bin/classes -d $(@D) org.musicpd.Bridge
+JAVA_CLASSFILES_DIR = android/build/classes
+
+$(ANDROID_XML_RES_COPIES): $(ANDROID_XML_RES)
+	@$(MKDIR_P) $(dir $@)
+	cp $(patsubst android/build/%,$(srcdir)/android/%,$@) $@
+
+android/build/resources.apk: $(ANDROID_XML_RES_COPIES) android/build/res/drawable/icon.png
+	@$(MKDIR_P) android/build/gen
+	$(AAPT) package -f -m --auto-add-overlay \
+		--custom-package org.musicpd \
+		-M $(srcdir)/android/AndroidManifest.xml \
+		-S android/build/res \
+		-J android/build/gen \
+		-I $(ANDROID_SDK_PLATFORM_DIR)/android.jar \
+		-F android/build/resources.apk
+
+# R.java is generated by aapt, when resources.apk is generated
+android/build/gen/org/musicpd/R.java: android/build/resources.apk
+
+android/build/classes.dex: $(JAVA_SOURCES) android/build/gen/org/musicpd/R.java
+	@$(MKDIR_P) $(JAVA_CLASSFILES_DIR)
+	$(JAVAC) -source 1.5 -target 1.5 -Xlint:-options \
+		-cp $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) \
+		-d $(JAVA_CLASSFILES_DIR) $^
+	$(DX) --dex --output $@ $(JAVA_CLASSFILES_DIR)
+
+android/build/include/org_musicpd_Bridge.h: android/build/classes.dex
+	javah -classpath $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) -d $(@D) org.musicpd.Bridge
 
 BUILT_SOURCES = android/build/include/org_musicpd_Bridge.h
 
-android/build/libs/armeabi-v7a/libmpd.so: libmpd.so android/build/build.xml
+android/build/lib/armeabi-v7a/libmpd.so: libmpd.so
 	mkdir -p $(@D)
 	rm -f $@
 	$(STRIP) -o $@ $<
@@ -325,21 +349,18 @@ android/build/res/drawable/icon.png: mpd.svg
 	mkdir -p $(@D)
 	rsvg-convert --width=48 --height=48 $< -o $@
 
-APK_DEPS = android/build/res/drawable/icon.png \
-	android/build/libs/armeabi-v7a/libmpd.so \
-	$(wildcard $(srcdir)/android/src/*.java) \
-	android/build/build.xml
+.DELETE_ON_ERROR: android/build/unsigned.apk
+android/build/unsigned.apk: android/build/classes.dex android/build/resources.apk android/build/lib/armeabi-v7a/libmpd.so
+	cp android/build/resources.apk $@
+	cd $(dir $@) && zip -q -r $(notdir $@) classes.dex lib
 
-android/build/bin/$(APK_NAME)-debug.apk: $(APK_DEPS)
-	cd android/build && ant nodeps debug
+android/build/$(APK_NAME)-debug.apk: android/build/unsigned.apk
+	jarsigner -keystore $(HOME)/.android/debug.keystore -storepass android -signedjar $@ $< androiddebugkey
 
-android/build/bin/$(APK_NAME)-release-unsigned.apk: $(APK_DEPS)
-	cd android/build && ant nodeps release
-
-android/build/bin/$(APK_NAME)-release-unaligned.apk: android/build/bin/$(APK_NAME)-release-unsigned.apk
+android/build/$(APK_NAME)-release-unaligned.apk: android/build/unsigned.apk
 	jarsigner -digestalg SHA1 -sigalg MD5withRSA -storepass:env ANDROID_KEYSTORE_PASS -keystore $(ANDROID_KEYSTORE) -signedjar $@ $< $(ANDROID_KEY_ALIAS)
 
-android/build/bin/$(APK_NAME).apk: android/build/bin/$(APK_NAME)-release-unaligned.apk
+android/build/$(APK_NAME).apk: android/build/$(APK_NAME)-release-unaligned.apk
 	$(ZIPALIGN) -f 4 $< $@
 
 endif
diff --git a/NEWS b/NEWS
index 3788d63a5..a6532fe62 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ ver 0.20.15 (not yet released)
 * state file
   - make mount point restore errors non-fatal
   - fix crash when restoring mounts with incompatible database plugin
+* Android
+  - build without Ant
 
 ver 0.20.14 (2018/01/01)
 * database