How to build gradle project for android programmatically
Here is an explanation of how to create an android gradle project importable by android studio for allegro library , this article is copied form this allegro forums thread : 'https://www.allegro.cc/forums/thread/617031' .
The aim is to create a tool for allegro library users to create android project simply , as told in the thread, we are trying to weaken the difficulities allegro users are facing when compiling for android .
Notes : - the tool is supposed to run from any folder of the filesystem , then it expects an environment variable to be set to 'ALLEGRO_ROOT' and from that folder the tool will pick the required files for project building ( templates ... ) and will also read the config files ...
Steps : ( Note , the following steps expalains how to build a gradle project using android tool from the sdk and allegro tool )
1 - call android tool : > android create project --activity ActivityName --path project_path --package org.allegro.game --target 1 --gradle --gradle-version 2.2.3 this is the prject structure :
Note : even if we told the android tool to build a gradle-friendly project , it wont be buildable by gradle , some changes sould be made on the project especially that we are going to use native code
2 - unfortunately , the sdk wont put a gradle-wrapper-zip file under '$(project_path)/gradle/wrapper' and that causes many build errors with gradle , we need to put our own , we get it from %ALLEGRO_ROOT% and put it at '$(project_folder)/gradle/wrapper/' , instead of copying the file each time from %ALLEGRO_ROOT% for the new project , a symbolic link to the orginal file is created , this will allow us to update the wrapper zip file for all projects created by the tool simplly by changing the orginal zip file in %ALLEGRO_ROOT% , that allow as to make the tool working with all future releaces of gradle
note : "gradle-3.2.1-all.zip" is used
3 - We trancate '$project_path)/gradle/wrapper/gradle-wrapper.properties' because the default one is not valide for the new versions of gradle
we do this : std::ofstream gradle_wrapper('$project_path)/gradle/wrapper/gradle-wrapper.properties'); gradle_wrapper<<"#Created by android.bat , edited by Allegro engine ."<<std::endl; gradle_wrapper<<"distributionBase=GRADLE_USER_HOME"<<std::endl; gradle_wrapper<<"distributionPath=wrapper/dists"<<std::endl; gradle_wrapper<<"zipStoreBase=GRADLE_USER_HOME"<<std::endl; gradle_wrapper<<"zipStorePath=wrapper/dists"<<std::endl; gradle_wrapper<<"distributionUrl=gradle-3.2.1-all.zip"<<std::endl;;
4 - in build.gradle replace "runProguard false" with "minifyEnabled true" , to avoid gradles's build errors related to Proguard
5 - in build.gradle we replace 'mavenCentral' with 'jcenter'
Note : time to create JniLibs folder & prepare for ndk-build ...
explained : the ndk_build command put the generated libs at $(project_path)/libs but 'gradle'&'android studio' uses '$(project_path)/JniLibs'
6 - we conserve '$(project_path)/libs' but we we create a symbolic link named 'JniLibs' under $(project_path) and now both tools will work ;) ( we really need them both to work ) Note : libs folder is not there yet , we need to create it for the symbolic link creation to work (ndk_build wont truncate it )
7 - create '$(project_path)/jni' folder ( Java native interface ) for native code
Note : now time to build jni internals
8 - create Application.mk under jni folder :
std::ofstream app_file('$(project_path)/jni/Application.mk'); app_file<<"APP_STL := gnustl_static"<<std::endl; app_file<<"APP_ABI := armeabi-v7a x86"<<std::endl; app_file<<"APP_PLATFORM := android-10"<<std::endl; app_file.close(); /// done
Note : we can copy it from a template under %ALLEGRO_ROOT% or create it depending on a preset tool's config file or depending n the command line arguments ....
9 - Create Android.mk under jni folder : we put this in Android.mk : 'include $(call all-subdir-makefiles)'
10 - under jni we create a symbolic link named 'libraries' and let it point to '%ALLEGRO_ROOT%/libraries' , there we find the prebuild allegro libraries for the target ABI of this project .... Note : we need to build an automated system to detect and put the desired exact libraries , these libraries will be copied to the apk and loaded at runtime by android os ( the JVM ) .
Note :now , time for user's code :
11 - we create a folder named 'src' , and under that folder we put the main.cpp template and we put the android.mk file with this content :
LOCAL_PATH := $(call my-dir)\n\ include $(CLEAR_VARS)\n\ LOCAL_MODULE := main\n\ LOCAL_CPPFLAGS += -fexceptions\n\ LOCAL_CPPFLAGS += -std=c++11\n\ LOCAL_C_INCLUDES := $(LOCAL_PATH)\n\ LOCAL_C_INCLUDES += $(ALLEGRO_ROOT)/include\n\ LOCAL_SRC_FILES := main.cpp \\\n\ LOCAL_SHARED_LIBRARIES := ALLEGRO_LIBS goes here\n\ include $(BUILD_SHARED_LIBRARY)
12 - now , there is two packages , one for allegro and the other for the user , the allegro package is allways the same , it is templated ، we will build it , by creating its folders under '$(project_path)\src\main' , so we create the folder : '$(project_path)\src\main\org.allegro.app' , why this package ? Because we gonna put allegro activity there and the user will import it from his package ( the user's package is created by android tool (step 1 )
13 - Now we have templates files for the 'main.cpp' , allegro.java' 'user.java' ( user activity inherits from allegro activity ) , and AndroidManifest.xml template , the problem is that those templates should be changed to match the package name and the activity name of the user , so we need to put 'ACTIVITY_NAME' &'PACKAGE_NAME' strings in those templates , and later we edit them to much this project's real activity and pachage name .
14 - we add the default allegro java file under the correspending folder inside allegro package
15 - we add the java file template under the correspending folder inside the user's package , as told in step 13 , those templaes are now edited to match this project , by replacing 'PACKAGE_NAME' by the user package name ....
16 - we create a file named AndroidManifest.xml under '$(project_path)\src\main\' , note : we should edit this file at step 13 to match this project by replacing 'PACKAGE_NAME' in the template with the users package name ... and by replacing ACTIVITY_NAME in the template by the user's project name set in the tool's Gui .
Note : the manifest file will point to the user's activity as an entry point of the app , and that activity will inherent from allegro's one , then the user will import allegro's package , so here we have an idea about the template java file of the user's activity how it's going to look .
17 - we excute : 'ndk-build & gradlew assembleDebug' and we are done and we have our game built , the apk is found in the project folder under outputs/apk
Notes : - 'gradlew.bat' ( '.bat' in windows case ) is a file generated by android tool , ( step 1 ) ,it is excuted to let gradle build the project , and you can also pass 'assembleRelease' also when executing it . - this project is not importable by android studio , and it can also be built on that IDE ( actually android studio will call also gradlew.bat ) - All template files exists under '%ALLEGRO_ROOT%/templates/android'