I’ve got two session this year, both related to Delphi mobile development, and both concerning how to reach out from the island that is the FM Application Framework (aka FMX aka FireMonkey) and gain access to the underlying mobile OS platform APIs.
The first session is Accessing the iOS API and looks at how Delphi-written iOS apps can talk to the CocoaTouch APIs and access additional iOS frameworks. We look at the Objective-C bridge and see how it is used to import iOS APIs, namely classes and protocols (Apple’s term for what we call interfaces), and how you can implement iOS interfaces and inherit from iOS classes. We also briefly look at how to pull in APIs that are not already imported by Delphi’s RTL. As a proof of concept we briefly see a Delphi iOS app that has no FMX code or units in it whatsoever, operating purely through the iOS APIs using the standard CocoaTouch model.
Files from the Accessing the iOS API session can be downloaded from here.
The second session is Accessing the Android API and looks at how Delphi-written Android apps can talk to the Android SDK classes. We look at the Java bridge and see how it is used to import Android APIs. We’ll also look at how to pull in APIs that are not already imported by Delphi’s RTL. We also look at how to add a splash screen to an Android app to cover up the startup time on anything other than the fastest devices, how to add Android menus to an app and how to launch external activities and get results back from them.
Files from the Accessing the Android API session can be downloaded from here. Take note that since several of the samples involve various required preliminary steps in order to function, as they step outside the comfort zone of Delphi XE5 RTM’s Android support, you should check the ReadMe.txt files supplied in the project directories of those projects.
[Update]
I plan to write up some of the subjects covered by these demos in further posts or articles as time and work schedules permit. However in the mean time I’ll respond to comments by expanding this post as necessary.
It appears that when the small Java source files get compiled, the Android dx tool expects them to be compiled by the JDK 1.6.x compiler as opposed to the JDK 1.7.x compiler. If you have JDK 1.7.x installed, you hit a problem with dx reporting:
bad class file magic (cafebabe) or version (0033.0000)
However, to avoid forcing a reinstall of JDK 1.6 you might like to modify my build.bat batch files and add in extra command line switches to the javac.exe command-lines. You need to insert this after the javac.exe command to force Java 1.6 byte code output, which is digestible by the Android dx command:
-source 1.6 -target 1.6
[Update 2]
Current write-ups:
- Splash screens are written up here for Delphi XE5 and Delphi XE6.
- Launching activities and getting results back is written up here for Delphi XE5 and Delphi XE6.
i tried to uses your build.bat but i cannot create dex file, i had this output:
ReplyDeleteC:\Users\test\Desktop\snippetandroid\Menu\java>build embarcadero.jar
Compiling the Java source files
Creating jar containing the new classes
Converting from jar to dex...
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/blong/test/NativeActivitySubclass.class
...while processing com/blong/test/NativeActivitySubclass.class
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/blong/test/SplashActivity$1.class
...while processing com/blong/test/SplashActivity$1.class
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/blong/test/SplashActivity.class
...while processing com/blong/test/SplashActivity.class
3 warnings
no classfiles specified
Merging dex files
Exception in thread "main" java.io.FileNotFoundException: C:\Users\test\Desktop\
snippetandroid\Menu\java\output\dex\new_classes.dex (The system cannot find the
file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:138)
at com.android.dx.io.DexBuffer.(DexBuffer.java:159)
at com.android.dx.merge.DexMerger.main(DexMerger.java:1073)
Tidying up
Could Not Find C:\Users\test\Desktop\snippetandroid\Menu\java\output\dex\new_cla
sses.dex
Now we have the end result, which is output\dex\classes.dex
C:\Users\test\Desktop\snippetandroid\Menu\java>build embarcadero.jar
Compiling the Java source files
Creating jar containing the new classes
Converting from jar to dex...
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/blong/test/NativeActivitySubclass.class
...while processing com/blong/test/NativeActivitySubclass.class
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/blong/test/SplashActivity$1.class
...while processing com/blong/test/SplashActivity$1.class
trouble processing:
bad class file magic (cafebabe) or version (0033.0000)
...while parsing com/blong/test/SplashActivity.class
...while processing com/blong/test/SplashActivity.class
3 warnings
no classfiles specified
Merging dex files
Exception in thread "main" java.io.FileNotFoundException: C:\Users\test\Desktop\
snippetandroid\Menu\java\output\dex\new_classes.dex (The system cannot find the
file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:138)
at com.android.dx.io.DexBuffer.(DexBuffer.java:159)
at com.android.dx.merge.DexMerger.main(DexMerger.java:1073)
Tidying up
Could Not Find C:\Users\test\Desktop\snippetandroid\Menu\java\output\dex\new_cla
sses.dex
Now we have the end result, which is output\dex\classes.dex
C:\Users\test\Desktop\snippetandroid\Menu\java>
what's the problem?
Interesting.
DeleteClearly the batch file has no error checking and carries on regardless.
My guess is, given I haven't seen these messages before, is that you have a different version of Java to me. In my program files directory I have a Java subdirectory. In there I have a jdk1.6.0_30 directory.
Do you, perhaps, have a JDK 1.7xx directory? I think Android tools may occasionally favour 1.6, but this is an educated guess at this point, without a spot of Internet searching.
Yeah, I've updated the text above to show how to work around this issue if you have JDK 1.7 installed. The Java 1.7 compiler emits different class formats than are expected and required by the Android dx tool.
DeleteOk thanks! I will try!
Deletei solved the problem but now when i tried to compile it on delphi i have another issue T.T :
Deletehttp://pastebin.com/ALhsdPzb
solved by adding manually drawable folder and on the menu "deployment" set remotepath as res\drawable and will work
DeleteWas the deployment not already set as that? Strikes me as odd that it wasn't.
DeleteAh, so the directory needed to exist, eh? I perhaps did that myself some time back.
All working now?
Thanks for sessions sir!,
ReplyDeleteBarton
You're welcome Barton - hopefully they were useful and/or interesting.
DeleteYes. 100% excellent. Thank you.
DeleteYes all worked well, need to exist on "res" folder another folder "drawable" and inside it we need "splash.png" . After it, I Added from the "deployment" menu the splash image (res/drawable/splash.png) and now set the remote path "res/drawable/". That's all what I didn't find on your source. Thanks for all the support. I will try something but is not very simple to to with this procedure.
ReplyDeleteThe deployment manager should have been set up to copy an image from within the Delphi installation folder into res/drawable/splash.png - did you not find that? I'm puzzled as to why you had to make a replacement deployment....
DeleteYes, I know it's not that straightforward, however whilst building your app you can switch the manifest back to he default activity for regular debugging. Then switch back near the end to have the splash screen back again.
Hi, any update for some example of an android services or broadcast receiver?
ReplyDeleteI'm trying to find some time to look into it!
Deleteah ok! i will wait impatiently :)
DeletePlease refer to http://blog.blong.com/2013/11/delphi-and-android-services.html for the time being
DeleteHi Brian, I can put the slash to work here, but when I finish my application seems to hang. If I call it again it delays and FC, so I see again the splash screen and everything goes fine.
ReplyDeleteI have changed the manifest template to reflect just like yours. My app finish with SharedActivity.finish.
Odd. What happens if you cut out the SharedActivity.finish, and exit the app with the Back key?
DeleteAlso, I dunno if it might require it, but have you tried calling finish from the Java thread, as oposed to the FMX thread?
Well, after some tries here I decided to remove the finish statement so it will let Android remove it from the memory when needed.
ReplyDeleteThe finish was inside the delphi and that was the main problem. After remove it, sometimes, very few times, app closes with FC, but could be something else.
Thank you!!
Hi Brian, I'm having trouble compiling the barcode scanning java files. I get the error: "NativeActivitySubclass.java:13: error: package com.embarcadero.firemonkey does not exist".
ReplyDeleteThis is presumably because I do not have embarcadero.jar. I searched the hard drive for it, but no luck. Can you help?
Apologies - I've now read the readme!
ReplyDeleteGlad you sorted it out Dave!
DeleteThank you very much for these sessions. I have downloaded the code and had no problems compiling for iOS. However, when I run on my iPhone 4S and click ListItem1, it says my screen resolution is 320 x 480 when it is actually 640 x 960 with its retina display. I suppose this is a bug in the FM library code but I am wondering if anyone is seeing the same thing when running on a phone and not the emulator.
ReplyDeleteI think what you're seeing is the difference between points and pixels. To enable apps to work on normal and hi-res displays, Apple doubled the pixel count but retained the same point count. Coordinates of controls can thus use the same values and appear in the same place, despite the pixel values differing. It's quite a neat solution to having 2 resolutions.
DeleteVery useful session and source !! Great job !!
ReplyDeleteBest regards
Mateusz
Thanks Mateusz - glad you found it/them useful!
DeleteHello,
ReplyDeletethanks for your great samples. Especially the Firemonkey-free apps are very interesting. Do you have similar app also for Android?
Bye,
Jürgen
I have ported one or two of the Android NDK samples for my personal amusement, so that I could get a flavour of how things worked. However it strikes me that you are more looking for a regular app running without FireMonkey, which I don't have - that would be very much a mix of Java and Pascal.
DeleteThe NDK demos are more full-screen demos like games would be, given that's more how the NDK is typically used.
I actually intend to do some game dev using Delphi, so an example where you could share the core code across both platforms, but have a render for iOS and one for Android would be useful. I suspect this would be a lot of work, but if you could do a sample app using it, it could well help kickstart a fair number of projects for people :)
DeleteI uninstall JDK1.7.0_25 and install JDK1.6.0_45.
ReplyDeleteException in thread "main" java.lang.NoClassDefFoundError: com/android/dx/merge/DexMerger
Caused by: java.lang.ClassNotFoundException: com.android.dx.merge.DexMerger
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: com.android.dx.merge.DexMerger.
SplashScreen working find!
ReplyDeleteI cant findGoogle samples how
i can add "keyclick" sound, when i bush button.
Can you help this broplems.
I think generally people include a sound file as a resource and use Android APIs to play the click sound file. I'm sure you can find information about how to play sound files in Android.
DeleteIn Delphi you can bundle the resource into the .apk using the deployment manager, and then feed the path to it into the pertinent API at runtime.
Warning to anyone who has applied Update 1 to XE5. You will need to re-run the batch job to create classes.dex. The symptoms of not doing so are obscure, e.g. odd selection behaviour in edit boxes and inability to type into them.
ReplyDeleteThanks for the tip.
DeleteI guess the Java code in classes.dex changed to match changes in the FMX/RTL in UP1 and the 2 need to be in sync, else a can of worms is opened up :o)
Hi Brian
ReplyDeleteIs there a way to include the zxing library (or any other 3rd party library) in the Delphi compiled apk so that users do not need to download it separately ?
Oliver, you can include any additional .jar files in the .apk, but calling them is another matter. It's cumbersome and verbose and does not have a "good" solution yet. There are a couple of published approaches, but they both involve manually coding up a lot of JNI fluff, which is very unpleasant.
DeleteSo in short, in manageable terms, no.
Hi Brian, Great presentation at coderage. In your iOS Api presentation, you did an example with Twebbrowser. Is there an simple way to add the following to Twebbrowser for both iOS & Android.
ReplyDelete1. Pinch and zoom
2. Setting the initial zoom size when you first load a page so that the entire page fits the screen.
Thanks
Hi, glad you enjoyed the session. Unfortunately I haven't really explored too much with the web browser so don't have a ready solution for that. I guess this isn't of much help?
DeleteThat is cool. I understand. Thanks for responding.
ReplyDeleteOh dear, the "I guess this isn't of much help?" comment was supposed to also include a URL. I wonder if it got stripped. It was meant to be: http://blogs.embarcadero.com/ao/2013/05/15/39460
DeleteHi
ReplyDeleteHow can I replay the Coderage 9 session "How to Get Reports on Mobile Devices" for Delphi. Currently, the only replay available for "How to Get Reports on Mobile Devices" is for C++.
Please, advise
Labels: c# barcode CodeRage Delphi IOS API
Hello. I wasn't involved in this CodeRage, so I'm not really sure if the session was delivered twice, for both Pascal and C++. It may well have been one session streamed twice for all I know - much as happened in CodeRage 8 for my IDE keystrokes talk. If there really was a Pascal version of the session, I'd like to think that its appearance ont he replay list is pending, but you may be best asking David I or Jim McKeeth about that.
DeleteBrian, I was reading your article because I need to use an API from Luxand for face recognition and I can't use the libreries. Itried with a jar file and i have an error.
ReplyDelete---------------------------
Debugger Exception Notification
---------------------------
Project Location.apk raised exception class EJNIException with message 'java.lang.NoClassDefFoundError: Luxand.FSDK$IFaceSDK'.
---------------------------
What i'm doing wrogn?
---------------------------
Sorry - didn't see the question for ages. Is the problem still current? I believe that error states that the .jar files that contain that appropriate nested interface are not successfully linked in. You might try using the java SDK tools to dump out the types in the .jar file to verify what exactly is there, and therefore what is not.
Delete