diff --git a/scripts/__image_snapshots__/e2e-installs-angular-instantsearch-favicon.png-snap.png b/scripts/__image_snapshots__/angular-instantsearch/src/favicon.png-snap.png
similarity index 100%
rename from scripts/__image_snapshots__/e2e-installs-angular-instantsearch-favicon.png-snap.png
rename to scripts/__image_snapshots__/angular-instantsearch/src/favicon.png-snap.png
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/drawable/product_placeholder.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/drawable/product_placeholder.png-snap.png
new file mode 100644
index 000000000..dde3e53d5
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/drawable/product_placeholder.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-hdpi/ic_launcher.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-hdpi/ic_launcher.png-snap.png
new file mode 100644
index 000000000..cde69bccc
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-hdpi/ic_launcher.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png-snap.png
new file mode 100644
index 000000000..9a078e3e1
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-mdpi/ic_launcher.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-mdpi/ic_launcher.png-snap.png
new file mode 100644
index 000000000..c133a0cbd
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-mdpi/ic_launcher.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png-snap.png
new file mode 100644
index 000000000..efc028a63
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png-snap.png
new file mode 100644
index 000000000..bfa42f0e7
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png-snap.png
new file mode 100644
index 000000000..3af2608a4
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png-snap.png
new file mode 100644
index 000000000..324e72cdd
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png-snap.png
new file mode 100644
index 000000000..9bec2e623
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png-snap.png
new file mode 100644
index 000000000..aee44e138
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png-snap.png differ
diff --git a/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png-snap.png b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png-snap.png
new file mode 100644
index 000000000..34947cd6b
Binary files /dev/null and b/scripts/__image_snapshots__/instantsearch-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png-snap.png differ
diff --git a/scripts/__image_snapshots__/e2e-installs-instantsearch.js-favicon.png-snap.png b/scripts/__image_snapshots__/instantsearch.js/favicon.png-snap.png
similarity index 100%
rename from scripts/__image_snapshots__/e2e-installs-instantsearch.js-favicon.png-snap.png
rename to scripts/__image_snapshots__/instantsearch.js/favicon.png-snap.png
diff --git a/scripts/__image_snapshots__/e2e-installs-react-instantsearch-favicon.png-snap.png b/scripts/__image_snapshots__/react-instantsearch/public/favicon.png-snap.png
similarity index 100%
rename from scripts/__image_snapshots__/e2e-installs-react-instantsearch-favicon.png-snap.png
rename to scripts/__image_snapshots__/react-instantsearch/public/favicon.png-snap.png
diff --git a/scripts/__image_snapshots__/e2e-installs-vue-instantsearch-favicon.png-snap.png b/scripts/__image_snapshots__/vue-instantsearch/favicon.png-snap.png
similarity index 100%
rename from scripts/__image_snapshots__/e2e-installs-vue-instantsearch-favicon.png-snap.png
rename to scripts/__image_snapshots__/vue-instantsearch/favicon.png-snap.png
diff --git a/scripts/__snapshots__/e2e-templates.test.js.snap b/scripts/__snapshots__/e2e-templates.test.js.snap
index 403ba7a82..bb8684500 100644
--- a/scripts/__snapshots__/e2e-templates.test.js.snap
+++ b/scripts/__snapshots__/e2e-templates.test.js.snap
@@ -945,6 +945,624 @@ Array [
]
`;
+exports[`Templates InstantSearch Android File content: .gitignore 1`] = `
+"# IDE Files
+*.iml
+.idea/*
+projectFilesBackup
+
+# Build
+.gradle
+/.idea/workspace.xml
+/.idea/libraries
+/build
+/captures
+
+# Local setup
+/local.properties
+
+# OS Files
+.DS_Store"
+`;
+
+exports[`Templates InstantSearch Android File content: app/.gitignore 1`] = `"/build"`;
+
+exports[`Templates InstantSearch Android File content: app/build.gradle 1`] = `
+"apply plugin: 'com.android.application'
+
+android {
+ dataBinding.enabled true
+ compileSdkVersion 27
+ buildToolsVersion '27.0.3'
+ defaultConfig {
+ applicationId \\"com.example.instantsearch.app\\"
+ minSdkVersion 15
+ targetSdkVersion 27
+ versionCode 1
+ versionName \\"1.0\\"
+ testInstrumentationRunner \\"android.support.test.runner.AndroidJUnitRunner\\"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ implementation 'com.android.support:appcompat-v7:27.1.1'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.2'
+ implementation 'com.example:instantsearch-android:1.12.0'
+ testImplementation 'junit:junit:4.12'
+}"
+`;
+
+exports[`Templates InstantSearch Android File content: app/proguard-rules.pro 1`] = `
+"# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/pln/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/androidTest/java/com/algolia/instantsearch/mvp/ExampleInstrumentedTest.java 1`] = `
+"package com.example.instantsearch.app;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals(\\"com.example.instantsearch.app\\", appContext.getPackageName());
+ }
+}"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/AndroidManifest.xml 1`] = `
+"
+
+
+
+
+
+
+
+
+
+
+
+
+"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/java/com/algolia/instantsearch/app/MainActivity.java 1`] = `
+"package com.example.instantsearch.app;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.example.instantsearch.helpers.Searcher;
+import com.example.instantsearch.helpers.InstantSearch;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String ALGOLIA_APP_ID = \\"appId\\";
+ private static final String ALGOLIA_SEARCH_API_KEY = \\"apiKey\\";
+ private static final String ALGOLIA_INDEX_NAME = \\"indexName\\";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ final Searcher searcher = Searcher.create(ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, ALGOLIA_INDEX_NAME);
+ final InstantSearch helper = new InstantSearch(this, searcher);
+ helper.search(); // First empty search to display default results
+ }
+}"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/java/com/algolia/instantsearch/mvp/MainActivity.java 1`] = `
+"package com.example.instantsearch.app;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.example.instantsearch.helpers.Searcher;
+import com.example.instantsearch.helpers.InstantSearch;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String ALGOLIA_APP_ID = \\"latency\\";
+ private static final String ALGOLIA_SEARCH_API_KEY = \\"3d9875e51fbd20c7754e65422f7ce5e1\\";
+ private static final String ALGOLIA_INDEX_NAME = \\"bestbuy\\";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ final Searcher searcher = Searcher.create(ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, ALGOLIA_INDEX_NAME);
+ final InstantSearch helper = new InstantSearch(this, searcher);
+ helper.search(); // First empty search to display default results
+ }
+}"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/res/layout/activity_main.xml 1`] = `
+"
+
+
+
+
+
+"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/res/layout/hits_item.xml 1`] = `
+"
+
+
+
+
+
+
+"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/res/values/colors.xml 1`] = `
+"
+
+ #3F51B5
+ #303F9F
+ #FF4081
+"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/res/values/strings.xml 1`] = `
+"
+ instantsearch-android-app
+"
+`;
+
+exports[`Templates InstantSearch Android File content: app/src/main/res/values/styles.xml 1`] = `
+"
+
+
+
+
+"
+`;
+
+exports[`Templates InstantSearch Android File content: build.gradle 1`] = `
+"// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ google()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.1.3'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ google()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}"
+`;
+
+exports[`Templates InstantSearch Android File content: gradle.properties 1`] = `
+"# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true"
+`;
+
+exports[`Templates InstantSearch Android File content: gradle/wrapper/gradle-wrapper.properties 1`] = `
+"#Tue Jul 03 16:02:11 CEST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\\\\://services.gradle.org/distributions/gradle-4.4-all.zip"
+`;
+
+exports[`Templates InstantSearch Android File content: gradlew 1`] = `
+"#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=\\"\\"
+
+APP_NAME=\\"Gradle\\"
+APP_BASE_NAME=\`basename \\"$0\\"\`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=\\"maximum\\"
+
+warn ( ) {
+ echo \\"$*\\"
+}
+
+die ( ) {
+ echo
+ echo \\"$*\\"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case \\"\`uname\`\\" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG=\\"$0\\"
+# Need this for relative symlinks.
+while [ -h \\"$PRG\\" ] ; do
+ ls=\`ls -ld \\"$PRG\\"\`
+ link=\`expr \\"$ls\\" : '.*-> \\\\(.*\\\\)$'\`
+ if expr \\"$link\\" : '/.*' > /dev/null; then
+ PRG=\\"$link\\"
+ else
+ PRG=\`dirname \\"$PRG\\"\`\\"/$link\\"
+ fi
+done
+SAVED=\\"\`pwd\`\\"
+cd \\"\`dirname \\\\\\"$PRG\\\\\\"\`/\\" >/dev/null
+APP_HOME=\\"\`pwd -P\`\\"
+cd \\"$SAVED\\" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n \\"$JAVA_HOME\\" ] ; then
+ if [ -x \\"$JAVA_HOME/jre/sh/java\\" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=\\"$JAVA_HOME/jre/sh/java\\"
+ else
+ JAVACMD=\\"$JAVA_HOME/bin/java\\"
+ fi
+ if [ ! -x \\"$JAVACMD\\" ] ; then
+ die \\"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation.\\"
+ fi
+else
+ JAVACMD=\\"java\\"
+ which java >/dev/null 2>&1 || die \\"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation.\\"
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ \\"$cygwin\\" = \\"false\\" -a \\"$darwin\\" = \\"false\\" ] ; then
+ MAX_FD_LIMIT=\`ulimit -H -n\`
+ if [ $? -eq 0 ] ; then
+ if [ \\"$MAX_FD\\" = \\"maximum\\" -o \\"$MAX_FD\\" = \\"max\\" ] ; then
+ MAX_FD=\\"$MAX_FD_LIMIT\\"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn \\"Could not set maximum file descriptor limit: $MAX_FD\\"
+ fi
+ else
+ warn \\"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\\"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS=\\"$GRADLE_OPTS \\\\\\"-Xdock:name=$APP_NAME\\\\\\" \\\\\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\\\\"\\"
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=\`cygpath --path --mixed \\"$APP_HOME\\"\`
+ CLASSPATH=\`cygpath --path --mixed \\"$CLASSPATH\\"\`
+ JAVACMD=\`cygpath --unix \\"$JAVACMD\\"\`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=\`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null\`
+ SEP=\\"\\"
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS=\\"$ROOTDIRS$SEP$dir\\"
+ SEP=\\"|\\"
+ done
+ OURCYGPATTERN=\\"(^($ROOTDIRS))\\"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ \\"$GRADLE_CYGPATTERN\\" != \\"\\" ] ; then
+ OURCYGPATTERN=\\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\\"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in \\"$@\\" ; do
+ CHECK=\`echo \\"$arg\\"|egrep -c \\"$OURCYGPATTERN\\" -\`
+ CHECK2=\`echo \\"$arg\\"|egrep -c \\"^-\\"\` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval \`echo args$i\`=\`cygpath --path --ignore --mixed \\"$arg\\"\`
+ else
+ eval \`echo args$i\`=\\"\\\\\\"$arg\\\\\\"\\"
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- \\"$args0\\" ;;
+ (2) set -- \\"$args0\\" \\"$args1\\" ;;
+ (3) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" ;;
+ (4) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" \\"$args3\\" ;;
+ (5) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" \\"$args3\\" \\"$args4\\" ;;
+ (6) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" \\"$args3\\" \\"$args4\\" \\"$args5\\" ;;
+ (7) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" \\"$args3\\" \\"$args4\\" \\"$args5\\" \\"$args6\\" ;;
+ (8) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" \\"$args3\\" \\"$args4\\" \\"$args5\\" \\"$args6\\" \\"$args7\\" ;;
+ (9) set -- \\"$args0\\" \\"$args1\\" \\"$args2\\" \\"$args3\\" \\"$args4\\" \\"$args5\\" \\"$args6\\" \\"$args7\\" \\"$args8\\" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=(\\"$@\\")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[\${#JVM_OPTS[*]}]=\\"-Dorg.gradle.appname=$APP_BASE_NAME\\"
+
+exec \\"$JAVACMD\\" \\"\${JVM_OPTS[@]}\\" -classpath \\"$CLASSPATH\\" org.gradle.wrapper.GradleWrapperMain \\"$@\\""
+`;
+
+exports[`Templates InstantSearch Android File content: gradlew.bat 1`] = `
+"@if \\"%DEBUG%\\" == \\"\\" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if \\"%OS%\\"==\\"Windows_NT\\" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if \\"%DIRNAME%\\" == \\"\\" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if \\"%ERRORLEVEL%\\" == \\"0\\" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:\\"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist \\"%JAVA_EXE%\\" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not \\"%OS%\\" == \\"Windows_NT\\" goto win9xME_args
+if \\"%@eval[2+2]\\" == \\"4\\" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if \\"x%~1\\" == \\"x\\" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\\\\gradle\\\\wrapper\\\\gradle-wrapper.jar
+
+@rem Execute Gradle
+\\"%JAVA_EXE%\\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \\"-Dorg.gradle.appname=%APP_BASE_NAME%\\" -classpath \\"%CLASSPATH%\\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if \\"%ERRORLEVEL%\\"==\\"0\\" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not \\"\\" == \\"%GRADLE_EXIT_CONSOLE%\\" exit 1
+exit /b 1
+
+:mainEnd
+if \\"%OS%\\"==\\"Windows_NT\\" endlocal
+
+:omega"
+`;
+
+exports[`Templates InstantSearch Android File content: settings.gradle 1`] = `"include ':app'"`;
+
+exports[`Templates InstantSearch Android Folder structure: contains the right files 1`] = `
+Array [
+ ".gitignore",
+ "app/.gitignore",
+ "app/build.gradle",
+ "app/proguard-rules.pro",
+ "app/src/androidTest/java/com/algolia/instantsearch/mvp/ExampleInstrumentedTest.java",
+ "app/src/main/AndroidManifest.xml",
+ "app/src/main/java/com/algolia/instantsearch/app/MainActivity.java",
+ "app/src/main/java/com/algolia/instantsearch/mvp/MainActivity.java",
+ "app/src/main/res/layout/activity_main.xml",
+ "app/src/main/res/layout/hits_item.xml",
+ "app/src/main/res/mipmap-hdpi/ic_launcher.png",
+ "app/src/main/res/mipmap-hdpi/ic_launcher_round.png",
+ "app/src/main/res/mipmap-mdpi/ic_launcher.png",
+ "app/src/main/res/mipmap-mdpi/ic_launcher_round.png",
+ "app/src/main/res/mipmap-xhdpi/ic_launcher.png",
+ "app/src/main/res/mipmap-xhdpi/ic_launcher_round.png",
+ "app/src/main/res/mipmap-xxhdpi/ic_launcher.png",
+ "app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png",
+ "app/src/main/res/mipmap-xxxhdpi/ic_launcher.png",
+ "app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png",
+ "app/src/main/res/values/colors.xml",
+ "app/src/main/res/values/strings.xml",
+ "app/src/main/res/values/styles.xml",
+ "build.gradle",
+ "gradle.properties",
+ "gradle/wrapper/gradle-wrapper.jar",
+ "gradle/wrapper/gradle-wrapper.properties",
+ "gradlew",
+ "gradlew.bat",
+ "settings.gradle",
+]
+`;
+
exports[`Templates InstantSearch iOS File content: .gitignore 1`] = `
"# Created by https://www.gitignore.io/api/swift
diff --git a/scripts/e2e-templates.test.js b/scripts/e2e-templates.test.js
index 9d274991c..6c9e97128 100644
--- a/scripts/e2e-templates.test.js
+++ b/scripts/e2e-templates.test.js
@@ -80,24 +80,29 @@ describe('Templates', () => {
});
test('File content', () => {
- generatedFiles.forEach(filePath => {
- if (['.png', '.ico', '.jpg'].includes(filePath.slice(-4))) {
- const image = fs.readFileSync(`${templatePath}/${filePath}`);
-
- expect(image).toMatchImageSnapshot({
- customSnapshotIdentifier: `e2e-installs-${
- templateConfig.templateName
- }-${path.basename(filePath)}`,
- });
- } else {
- const fileContent = fs
- .readFileSync(`${appPath}/${filePath}`)
- .toString()
- .trim();
-
- expect(fileContent).toMatchSnapshot(filePath);
- }
- });
+ generatedFiles
+ .filter(filePath => !['.jar'].includes(filePath.slice(-4)))
+ .forEach(filePath => {
+ if (['.png', '.ico', '.jpg'].includes(filePath.slice(-4))) {
+ const image = fs.readFileSync(`${templatePath}/${filePath}`);
+
+ expect(image).toMatchImageSnapshot({
+ customSnapshotsDir: path.resolve(
+ `./scripts/__image_snapshots__/${
+ templateConfig.templateName
+ }/${path.dirname(filePath)}`
+ ),
+ customSnapshotIdentifier: path.basename(filePath),
+ });
+ } else {
+ const fileContent = fs
+ .readFileSync(`${appPath}/${filePath}`)
+ .toString()
+ .trim();
+
+ expect(fileContent).toMatchSnapshot(filePath);
+ }
+ });
});
});
});
diff --git a/src/api/__tests__/__snapshots__/index.test.js.snap b/src/api/__tests__/__snapshots__/index.test.js.snap
index 332042961..65675d7f5 100644
--- a/src/api/__tests__/__snapshots__/index.test.js.snap
+++ b/src/api/__tests__/__snapshots__/index.test.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Options with unknown template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, InstantSearch iOS, InstantSearch.js, React InstantSearch, React InstantSearch Native, Vue InstantSearch"`;
+exports[`Options with unknown template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, InstantSearch Android, InstantSearch iOS, InstantSearch.js, React InstantSearch, React InstantSearch Native, Vue InstantSearch"`;
exports[`Options with unvalid name throws 1`] = `
"Could not create a project called \\"[31m./WrongNpmName[39m\\" because of npm naming restrictions.
@@ -8,8 +8,8 @@ exports[`Options with unvalid name throws 1`] = `
- name can only contain URL-friendly characters"
`;
-exports[`Options with wrong template path throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, InstantSearch iOS, InstantSearch.js, React InstantSearch, React InstantSearch Native, Vue InstantSearch"`;
+exports[`Options with wrong template path throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, InstantSearch Android, InstantSearch iOS, InstantSearch.js, React InstantSearch, React InstantSearch Native, Vue InstantSearch"`;
exports[`Options without path throws 1`] = `"The option \`path\` is required."`;
-exports[`Options without template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, InstantSearch iOS, InstantSearch.js, React InstantSearch, React InstantSearch Native, Vue InstantSearch"`;
+exports[`Options without template throws 1`] = `"The template directory must contain a configuration file \`.template.js\` or must be one of those: Angular InstantSearch, InstantSearch Android, InstantSearch iOS, InstantSearch.js, React InstantSearch, React InstantSearch Native, Vue InstantSearch"`;
diff --git a/src/tasks/android/teardown.js b/src/tasks/android/teardown.js
new file mode 100644
index 000000000..01c3b8645
--- /dev/null
+++ b/src/tasks/android/teardown.js
@@ -0,0 +1,19 @@
+const chalk = require('chalk');
+
+module.exports = function teardown(config) {
+ if (!config.silent) {
+ console.log();
+ console.log(
+ `🎉 Created ${chalk.bold.cyan(config.name)} at ${chalk.green(
+ config.path
+ )}.`
+ );
+ console.log();
+
+ console.log('Begin by opening the new project.');
+ console.log();
+ console.log('⚡️ Start building something awesome!');
+ }
+
+ return Promise.resolve();
+};
diff --git a/src/tasks/common/build.js b/src/tasks/common/build.js
index f18909241..18d277577 100644
--- a/src/tasks/common/build.js
+++ b/src/tasks/common/build.js
@@ -14,23 +14,28 @@ module.exports = function build(config) {
// Add the `.hbs` extension to any templating files that need
// their placeholders to get filled with `metalsmith-in-place`
rename([
+ // `npx` renames `.gitignore` files to `.npmignore`
+ // See https://github.com/algolia/create-instantsearch-app/issues/48
+ ['.gitignore.template', '.gitignore'],
+ [/\.md$/, '.md.hbs'],
+ [/\.json$/, '.json.hbs'],
+ // For the web
+ [/\.webmanifest$/, '.webmanifest.hbs'],
[/\.html$/, '.html.hbs'],
[/\.css$/, '.css.hbs'],
[/\.js$/, '.js.hbs'],
[/\.ts$/, '.ts.hbs'],
[/\.vue$/, '.vue.hbs'],
- [/\.swift$/, '.swift.hbs'],
- [/\.md$/, '.md.hbs'],
- [/\.json$/, '.json.hbs'],
- [/\.webmanifest$/, '.webmanifest.hbs'],
// Use `.babelrc.template` as name to not trigger babel
// when requiring the file `.template.js` in end-to-end tests
// and rename it `.babelrc` afterwards
['.babelrc.template', '.babelrc'],
- // `npx` renames `.gitignore` files to `.npmignore`
- // See https://github.com/algolia/create-instantsearch-app/issues/48
- ['.gitignore.template', '.gitignore'],
['.eslintrc.js.hbs', '.eslintrc.js'],
+ // For iOS
+ [/\.swift$/, '.swift.hbs'],
+ // For Android
+ [/\.java$/, '.java.hbs'],
+ [/\.xml$/, '.xml.hbs'],
])
)
.use(inPlace())
diff --git a/src/templates/InstantSearch Android/.gitignore.template b/src/templates/InstantSearch Android/.gitignore.template
new file mode 100644
index 000000000..a343e7c75
--- /dev/null
+++ b/src/templates/InstantSearch Android/.gitignore.template
@@ -0,0 +1,17 @@
+# IDE Files
+*.iml
+.idea/*
+projectFilesBackup
+
+# Build
+.gradle
+/.idea/workspace.xml
+/.idea/libraries
+/build
+/captures
+
+# Local setup
+/local.properties
+
+# OS Files
+.DS_Store
diff --git a/src/templates/InstantSearch Android/.template.js b/src/templates/InstantSearch Android/.template.js
new file mode 100644
index 000000000..fbd1d1ba0
--- /dev/null
+++ b/src/templates/InstantSearch Android/.template.js
@@ -0,0 +1,11 @@
+const setup = require('../../tasks/ios/setup');
+const install = require('../../tasks/ios/install');
+const teardown = require('../../tasks/android/teardown');
+
+module.exports = {
+ templateName: 'instantsearch-android',
+ appName: 'instantsearch-android-app',
+ tasks: {
+ teardown,
+ },
+};
diff --git a/src/templates/InstantSearch Android/app/.gitignore.template b/src/templates/InstantSearch Android/app/.gitignore.template
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/.gitignore.template
@@ -0,0 +1 @@
+/build
diff --git a/src/templates/InstantSearch Android/app/build.gradle b/src/templates/InstantSearch Android/app/build.gradle
new file mode 100644
index 000000000..ecd78673d
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+
+android {
+ dataBinding.enabled true
+ compileSdkVersion 27
+ buildToolsVersion '27.0.3'
+ defaultConfig {
+ applicationId "com.example.instantsearch.app"
+ minSdkVersion 15
+ targetSdkVersion 27
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ implementation 'com.android.support:appcompat-v7:27.1.1'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.2'
+ implementation 'com.example:instantsearch-android:1.12.0'
+ testImplementation 'junit:junit:4.12'
+}
diff --git a/src/templates/InstantSearch Android/app/proguard-rules.pro b/src/templates/InstantSearch Android/app/proguard-rules.pro
new file mode 100644
index 000000000..dd2744751
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/pln/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/src/templates/InstantSearch Android/app/src/androidTest/java/com/algolia/instantsearch/mvp/ExampleInstrumentedTest.java b/src/templates/InstantSearch Android/app/src/androidTest/java/com/algolia/instantsearch/mvp/ExampleInstrumentedTest.java
new file mode 100644
index 000000000..6ed40551e
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/androidTest/java/com/algolia/instantsearch/mvp/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.instantsearch.app;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.example.instantsearch.app", appContext.getPackageName());
+ }
+}
diff --git a/src/templates/InstantSearch Android/app/src/main/AndroidManifest.xml b/src/templates/InstantSearch Android/app/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..04ef3a3cb
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/templates/InstantSearch Android/app/src/main/java/com/algolia/instantsearch/app/MainActivity.java b/src/templates/InstantSearch Android/app/src/main/java/com/algolia/instantsearch/app/MainActivity.java
new file mode 100644
index 000000000..3aed07aca
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/java/com/algolia/instantsearch/app/MainActivity.java
@@ -0,0 +1,22 @@
+package com.example.instantsearch.app;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.example.instantsearch.helpers.Searcher;
+import com.example.instantsearch.helpers.InstantSearch;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String ALGOLIA_APP_ID = "{{appId}}";
+ private static final String ALGOLIA_SEARCH_API_KEY = "{{apiKey}}";
+ private static final String ALGOLIA_INDEX_NAME = "{{indexName}}";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ final Searcher searcher = Searcher.create(ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, ALGOLIA_INDEX_NAME);
+ final InstantSearch helper = new InstantSearch(this, searcher);
+ helper.search(); // First empty search to display default results
+ }
+}
diff --git a/src/templates/InstantSearch Android/app/src/main/java/com/algolia/instantsearch/mvp/MainActivity.java b/src/templates/InstantSearch Android/app/src/main/java/com/algolia/instantsearch/mvp/MainActivity.java
new file mode 100644
index 000000000..e626bf991
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/java/com/algolia/instantsearch/mvp/MainActivity.java
@@ -0,0 +1,22 @@
+package com.example.instantsearch.app;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.example.instantsearch.helpers.Searcher;
+import com.example.instantsearch.helpers.InstantSearch;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String ALGOLIA_APP_ID = "latency";
+ private static final String ALGOLIA_SEARCH_API_KEY = "3d9875e51fbd20c7754e65422f7ce5e1";
+ private static final String ALGOLIA_INDEX_NAME = "bestbuy";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ final Searcher searcher = Searcher.create(ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, ALGOLIA_INDEX_NAME);
+ final InstantSearch helper = new InstantSearch(this, searcher);
+ helper.search(); // First empty search to display default results
+ }
+}
diff --git a/src/templates/InstantSearch Android/app/src/main/res/layout/activity_main.xml b/src/templates/InstantSearch Android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 000000000..4884d2314
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/src/templates/InstantSearch Android/app/src/main/res/layout/hits_item.xml b/src/templates/InstantSearch Android/app/src/main/res/layout/hits_item.xml
new file mode 100644
index 000000000..8dee7e635
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/res/layout/hits_item.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..9a078e3e1
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..efc028a63
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..3af2608a4
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..9bec2e623
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..aee44e138
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..34947cd6b
Binary files /dev/null and b/src/templates/InstantSearch Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/src/templates/InstantSearch Android/app/src/main/res/values/colors.xml b/src/templates/InstantSearch Android/app/src/main/res/values/colors.xml
new file mode 100644
index 000000000..3ab3e9cbc
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/src/templates/InstantSearch Android/app/src/main/res/values/strings.xml b/src/templates/InstantSearch Android/app/src/main/res/values/strings.xml
new file mode 100644
index 000000000..71628bb45
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ {{name}}
+
diff --git a/src/templates/InstantSearch Android/app/src/main/res/values/styles.xml b/src/templates/InstantSearch Android/app/src/main/res/values/styles.xml
new file mode 100644
index 000000000..5885930df
--- /dev/null
+++ b/src/templates/InstantSearch Android/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/src/templates/InstantSearch Android/build.gradle b/src/templates/InstantSearch Android/build.gradle
new file mode 100644
index 000000000..ad6a92810
--- /dev/null
+++ b/src/templates/InstantSearch Android/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ google()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.1.3'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ google()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/src/templates/InstantSearch Android/gradle.properties b/src/templates/InstantSearch Android/gradle.properties
new file mode 100644
index 000000000..aac7c9b46
--- /dev/null
+++ b/src/templates/InstantSearch Android/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/src/templates/InstantSearch Android/gradle/wrapper/gradle-wrapper.jar b/src/templates/InstantSearch Android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..13372aef5
Binary files /dev/null and b/src/templates/InstantSearch Android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/src/templates/InstantSearch Android/gradle/wrapper/gradle-wrapper.properties b/src/templates/InstantSearch Android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..6fb970cb1
--- /dev/null
+++ b/src/templates/InstantSearch Android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jul 03 16:02:11 CEST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/src/templates/InstantSearch Android/gradlew b/src/templates/InstantSearch Android/gradlew
new file mode 100755
index 000000000..9d82f7891
--- /dev/null
+++ b/src/templates/InstantSearch Android/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/src/templates/InstantSearch Android/gradlew.bat b/src/templates/InstantSearch Android/gradlew.bat
new file mode 100644
index 000000000..8a0b282aa
--- /dev/null
+++ b/src/templates/InstantSearch Android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/templates/InstantSearch Android/settings.gradle b/src/templates/InstantSearch Android/settings.gradle
new file mode 100644
index 000000000..e7b4def49
--- /dev/null
+++ b/src/templates/InstantSearch Android/settings.gradle
@@ -0,0 +1 @@
+include ':app'