Saturday, 14 October 2017

Delphi build/install/launch Android app from the command-line

Quite some while back I answered a question on Stack Overflow, which explained how to build a Delphi project from the command line and also how to deploy it. The context of the question was Andriod development

In the case of an Android application deploying it has absolutely nothing to do with installing the resultant .apk file onto your Android device, despite what your personal interpretation of the word may be. Oh no, most definitely not.

Instead, deployment is about packaging up all your various files - your compiled Android library (a .so file), all the images, splash screens, icons, custom files, databases, application manifest file and so forth – all into an .apk file. In other words as far as the Delphi IDE is concerned, deploying a Delphi project means going from a .so native ARM library to an installable .apk file.

Clearly when you press F9 or Ctrl+Shift+F9 to run your application the IDE works out how to install your .apk on the currently connected and selected device, but that is subsequent to the IDE’s notion of the deployment step.

So, installation notwithstanding, that SO answer shows how to make/build and deploy a Delphi project, such as an Android project, from a RAD Studio command prompt:

To recap on it this does a build:

msbuild Foo.dproj /p:Config=Debug /p:Platform=Android /t:Build

This does a make, which only compiles files that have changed:

msbuild Foo.dproj /p:Config=Debug /p:Platform=Android /t:Make

This step, assuming you have done a deployment at least once in the IDE and thereby have had a Foo.deployproj file generated, will do the deployment:

msbuild Foo.dproj /p:Config=Debug /p:Platform=Android /t:Deploy

If you have the .deployproj file you can combine the two steps in this one command (excuse any line wrapping this blog theme applies):

msbuild Foo.dproj /p:Config=Debug /p:Platform=Android /t:Make;Deploy

[Update – 16/10/2-17:

I also bumped into the property that controls the Target Configuration, which can be Development or Application Store for Android. The BT_BuildType can either be Debug or AppStore for Android (for iOS there is also AdHoc. So if you want to build a signed app ready for upload to the Google Play store you could run:

msbuild Foo.dproj /p:Config=Release /p:Platform=Android /t:Make;Deploy /p:BT_BuildType=AppStore

End Update ]

So anyway, history to one side, I was wondering if there was another MSBuild target that did the installation, or if this was some custom code in the IDE, not exposed through MSBuild. My investigation suggests the latter to be the case, but I wanted a convenient command-line way to make, deploy and install the Android application (and even possibly launch it!).

The best option I could rustle up at short notice was a batch file (or command script, if you prefer). Save the file below as BuildAndInstall.bat or BuildAndInstall.cmd, set up any of the paths etc. that need personalising to your system.

Again, please excuse unsolicited line wrapping…. There is probably a nifty way to get this code into a horizontally scrollable div or similar, but I don’t have the time to do the research just now….

@echo off
rem Syntax
rem  Arg 1 = project name
rem  Arg 2 (optional) = build configuration
rem  Arg 3 (optional) = package name
set ANDROID_SDK=%PUBLIC%\Documents\Embarcadero\Studio\19.0\PlatformSDKs\android-sdk-windows
set ADB=%ANDROID_SDK%\platform-tools\adb.exe
set FQ_PROJECT=%~f1
set PROJECT_DIR=%~p1
set PROJECT_NAME=%~n1
set PACKAGE_NAME=com.embarcadero.%PROJECT_NAME%
set CONFIG=Debug
if X%1 == X goto syntax
if not exist %1 (
  echo Cannot locate project %FQ_PROJECT%
  goto :EOF
)
if not X%2 == X (
  if "%2" == "Release" set CONFIG=Release
)
if not X%3 == X (
  set PACKAGE_NAME=%3
)
pushd %PROJECT_DIR%
echo.&echo Building %1&echo.
msbuild %PROJECT_NAME%.dproj /p:Config=%CONFIG% /p:Platform=Android /t:Make || goto build_error
echo.&echo Deploying %1&echo.
msbuild %PROJECT_NAME%.dproj /p:Config=%CONFIG% /p:Platform=Android /t:Deploy || goto deploy_error
echo.&echo Installing Android package&echo.
%ADB% install -r Android\%CONFIG%\%PROJECT_NAME%\bin\%PROJECT_NAME%.apk || goto install_error
echo.&echo Launching Android app&echo.
%ADB% -d shell am start -a android.intent.action.MAIN -n %PACKAGE_NAME%/com.embarcadero.firemonkey.FMXNativeActivity || goto launch_error
popd
echo.&echo Done!
goto :EOF
:syntax
echo BuildAndInstall syntax:
echo.
echo   BuildAndInstall ^<DelphiProjectFile^> [^<Configuration^> [^<AndroidPackageName^>]]
echo.
echo where:
echo.
echo ^<DelphiprojectFile^> is a Delphi project.dproj file
echo ^<Configuration^> is the required build configuration, Release or Debug, which defaults to Debug
echo ^<AndroidPackageName^> is the Android package name for the project, in case it is different from com.embarcadero.project
goto :EOF
:build_error
echo Problem encountered while build the Android lib%PROJECT_NAME%.so native library
goto :EOF
:deploy_error
echo Problem encountered while creating the %PROJECT_NAME%.apk Android package
goto :EOF
:install_error
echo Problem encountered while installing %PROJECT_NAME%.apk
goto :EOF
:launch_error
echo Problem encountered while launching %PROJECT_NAME%.apk
goto :EOF

If you young pups reading this are all into relatively modern PowerShell scripting or traditional Windows scripting, then this throwback to the world of DOS may fall uneasily on the eye, but it works and there is a lot of power available in DOS scripting commands.

[ Update – 16/10/2017: I initially forgot to mention that you’d be wise to run this from a RAD Studio Command Prompt for the version of RAD Studio that you want to build your project. This ensures that the Windows search path is set up to find the correct compilers etc. Alternatively, at the top of my batch file you can do the equivalent of running a RAD Studio Command Prompt by inserting:

CALL C:\Program Files (x86)\Embarcadero\Studio\19.0\bin\rsvars.bat

If you choose this latter option then you can use any old command prompt you like.

End Update ]

Now you can install and run an Android project with a command-line of:

BuildAndInstall Foo.dproj

if you want the release build, use:

BuildAndInstall Foo.dproj Release

If you’ve changed the package name (specified as package in the project options Version Info page) from the default com.embarcadero.Foo then to launch the app you’ll need to pass the package name on the command line:

BuildAndInstall Foo.dproj Debug com.blong.Foo

Don’t forget that you will have to choose Project, Deploy libProjectname.so in the IDE menus once before this will work.

I hope this is of use to someone….

14 comments:

  1. Wow, Great. This is particularly useful as I normally use Tokyo but have to build my Android projects using Berlin as Tokyo has so many Android problems. One question though is how do I ensure that the Berlin version is used?

    ReplyDelete
    Replies
    1. Ah, so I may have forgotten to write in there to run the batch file from a RAD Studio Command Prompt. In which case you just use a Berlin RAD Studio Command prompt. However, you can also add - CALL path_to_BDS_bin\rsvars.bat - at the top. All this assumes you *don't* have any of the BDS bin directories on your PATH already.

      Can you elaborate on the Android issues you face? Is this even after having installed the 10.2.1 release?

      Delete
  2. 3D objects are completely skewed

    ReplyDelete
    Replies
    1. Is this issue 'known' - i.e. are there current QP reports on it, do you know? I am not familiar with it.

      Delete
  3. If I have to open up Berlin to do it then I may as well build and deploy from within it. I was hoping to somehow avoid that.

    ReplyDelete
    Replies
    1. >>If I have to open up Berlin to do it then I may as well build and deploy from within it. I was hoping to somehow avoid that.

      You don't need to open the IDE. The RAD Studio Command prompt is a shortcut in the Start menu program group for RAD Studio that runs up a command prompt, and auto-run's the rsvars.bat script from its bin directory in order to set the PATH up to ensure the right compilers etc. are located.

      You don't even need to run that if you don't want. As I mentioned, in the earlier comment you can just call that rsvars.bat batch file explicitly at the top of my batch file to set the search paths up. This then satisfies your initial requirement of ensuring that the right compilers are used when you want to build with a certain version (i.e. Berlin).

      The only requirement to open any IDE is a one-off to get the .deployproj file created. Without .deployproj (which seems only able to be created by the IDE) then you cannot deploy from the command prompt.

      Let me know if I'm still not being clear enough and I'll try to explain better.

      Delete
  4. Thanks. I've tried both ways but when doing the build I am getting the error MSB4079: The element occurs more than once.

    ReplyDelete
    Replies
    1. Sometimes Delphi breaks the project file by inserting a second (empty) ProjectExtensions element. The command line compilers seem rather more sensitive to it than the IDE for some reason. Take a look in your .dproj file and count the number of ProjectExtensions nodes. If there are two, then that's one too many and you ought to delete the empty one.

      BTW, I'm assuming this is a ProjectExtensions issue - the use of angle brackets in your comment has caused the blog engine to strip it out as unknown markup.

      Delete
  5. Thanks Brian. Yes, deleting the additional line did resolve the problem.

    ReplyDelete
  6. Thanks again. This saves me so much time and avoids me mistakenly uploading an app to google play store that doesn't work. I wish I'd seen your first post on the subject :)

    ReplyDelete
    Replies
    1. You're welcome - I'm glad to see it's of use to others in addition to just myself (o:

      Delete
    2. BTW Ken, I just updated the post to include mention of the MSBuild property to control whether an app store (Google Play) build will be done or a development build. That may be germane to your use case.
      You might need to do a spot of work on my batch file to incorporate it properly.

      Delete