Categories
Android MVP Source Code

Every Android API for Delphi

Delphi XE5’s support for Android includes many of the most common Android APIs either wrapped in nice cross platform libraries and component or accessible directly via the JNI wrappers. The rest can be accessed by creating headers to expose them. The new JNI Bridge makes this calling of the managed Java APIs from the native Delphi app much easier then it used to be, but it still takes a little effort to make the translation (it is easier than translating a Windows API). Brian Long (an Embarcadero MVP) has an excellent video from CodeRage 8 that goes into great detail on the process.

But all of that has now changed. CHUA Chee Wee aka “Chewy” (also an Embarcadero MVP) has released an Android2DelphiImport tool that makes wrapping and accessing any and every Android API much easier. It gives you 3 distinct benefits:

  1. You can point it at Android.jar in the Android SDK and have it create wrappers for EVERY Android API. You’ll need to copy and paste out the pieces you want (it puts them all in one source file), but it saves a lot of typing and research. It implements the wrapper using the JNI Bridge just like the RTL does.
  2. You can point it at any other built in Java library, like the Google Glass GDK that provides all the Glass specific features on Google Glass, or maybe the Google Cloud Messaging (GCM) API. You’ll have a source file that wraps all the API calls exposed in that JAR file.
  3. You can use it to wrap a 3rd party Java JAR file for Android and it will create a .PAS interface for it, bundle it up for inclusion in your Delphi app, and load it at runtime.

As a matter of testing this tool I pointed it the Android.jar file for Kit Kat. It took a little while, but when it was done I had over 100,000 lines of interface wrappers covering EVERY Android API on Kit Kit. I copied out the lines for Toast support, added in the necessary uses statements, and I had full toast support in just a few minutes.

My next test was to point it to the Google Glass GDK (Glass Development Kit) for building native Glass Apps. Previously I had only used the Android SDK & NDK, which supports the common Android functionality on Glass, but the GDK adds support for Glass specific features. Once the GDK is installed (via the Android SDK Manager under API 15) you will find gdk.jar in the sdk\add-ons\addon-google_gdk-google-15\libs folder. It created a nice wrapper for it, but that wrapper wouldn’t compile because the uses clause was incomplete (it has a notice that you need to adjust the uses clause). I had to track down 4 additional units for the uses clause and then I extracted 3 more apis from the earlier Android wrapper to cover APIs that weren’t previously exposed. In all it took me about 15 minutes and then I had full support for the Google Glass GDK.

Since compiling isn’t enough, I built a simple app to insert and remove cards on the Google Glass timeline. It worked like a charm. I didn’t need to tweak or adjust the generated code at all (beyond the uses clause). Here is my code:

tm := TJTimelineManager.JavaClass.from(SharedActivityContext);
card := TJCard.JavaClass.Init(SharedActivityContext);
card.setText(StringToJString('Hello Glass'));
card.setFootnote(StringToJString('From Delphi'));
id := tm.insert(card); // Use id to edit or remove card later

I haven’t tested the 3rd scenario yet, but I did observe how it works. The tool creates a .apk out of the selected JAR file. It then includes a routine to load that APK at runtime so you can call into the methods it includes. You would need to go this route when the JAR isn’t built into the platform already. I have a library that I’m planning to test this with (so stay tuned), but I wanted to blog about the other benefits right way.

I am really excited about the potential of this tool. Not only does this mean you have even easier access to the entire Android API, but you also have easy access to all the extended APIs and 3rd party APIs. It has a simple command-line interface, and very few options, but when it works that is all you need.

Right now purchasing it is a little more complicated than using it. He only accepts Bitcoins, 1/4 Bitcoin to be exact. Based on the current exchange rate it is about $200 US, which is an excellent value for what you get (and considering how much effort has gone into its development). So you will either need to mine or purchase a bitcoin to pick this tool up, but if you are doing Android development I highly recommend it.

15 replies on “Every Android API for Delphi”

Every API, really? Included those who use functionality the JNI bridge cannot yet support like inheriting from Java classes or broadcast receivers used in ANdroidBluetoothAdapter class, which are required for device search.

Radek: I believe he is requesting that you don’t just distribute all the output since there is a finite amount of APIs. I’d suggest you check with him.

Isn’t this the kind of tool that ought to have been included “in the box” with Delphi? Good work by Chewy, but the extent to which the community has to constantly step up and fill gaps in functionality in the core product (documentation, logging, profiling, unit testing, code coverage, stack trace, etc.) is ridiculous. Imagine what the community could produce if it could concentrate on higher-level functionality rather than core functionality.

It would be great to include a tool like this “in the box”, but the issue comes down to dealing with corner cases. If you’ve ever shipped any kind of software you know that the basic functionality is easy. Then dealing with all the contingencies and unexpected situations is where all the time is spent. A simple tool that wraps most APIs successfully is great, but making sure that tool works in every scenario is a lot more work. I haven’t tested Chewy’s tool to make sure it converted every API successfully, but I would expect there are some scenarios where it fails (just because of the breadth of possible APIs). I’m sure it will get close, and it will be helpful in all situations, but it will not always be perfect (for example requiring that I manually edit the uses clause).

Now if such a tool was included as a product feature then it would be expected that it always gets the uses clause right, and it supports every API out there. For every Java API it doesn’t support completely there would be a bug report generated. All these bug reports for niche APIs would distract from the core functionality of the product.

This is my opinion from working on a lot of different software products, and not necessarily the decision making process that occurs within R&D or Product management. I’d love for them to prove me wrong and include such a tool.

To the “in the box” topic: there have been and are various parts in the product where I’d expect it to deal properly with corner case and work properly but where that part of the product didn’t for several releases. Or put better: was quite buggy from the start. One of the areas which come up in my mind is “audits”. It was full of false positives which renders the affected audits quite useless. Nowadays it’s better but still not 100%. But it’s in the core product and I’d expect it to work properly. So some things are included even in that state and others are rejected because they possibly have some problems in some corner cases. Looks to me like double standard is being applied here.

Hello!
I am trying to do:
http://developer.android.com/training/managing-audio/audio-focus.html

I have this:

C:\Program Files (x86)\Embarcadero\Studio\16.0\source\rtl\android\Androidapi.JNI.Media.pas

JAudioManager_OnAudioFocusChangeListenerClass = interface(IJavaClass)
[‘{D79C0846-0031-48D5-9EB0-A995A3D034A2}’]
end;

[JavaSignature(‘android/media/AudioManager$OnAudioFocusChangeListener’)]
JAudioManager_OnAudioFocusChangeListener = interface(IJavaInstance)
[‘{F6FE80F4-5596-4E41-B718-BFEEEDBFAE47}’]
procedure onAudioFocusChange(focusChange: Integer); cdecl;
end;
TJAudioManager_OnAudioFocusChangeListener = class(TJavaGenericImport) end;

I need to use this to know when my app has audio focus.

I am doing so:

var
myAudioMgr : JAudioManager;
_aa : JAudioManager_OnAudioFocusChangeListener;

….
Form Create:

obj := SharedActivityContext.getSystemService(TJContext.JavaClass.AUDIO_SERVICE);
myAudioMgr := TJAudioManager.Wrap((obj as ILocalObject).GetObjectID);

myAudioMgr.requestAudioFocus(_aa,
TJAudioManager.JavaClass.STREAM_MUSIC,
TJAudioManager.JavaClass.AUDIOFOCUS_GAIN);

_aa.myOnAudioFocusChange := self.onMyAudioFocusChange;

….
procedure TForm1.onMyAudioFocusChange(focusChange: System.Integer);
begin
Log.Add(focusChange);
end;

I have error when compile this line:
_aa.myOnAudioFocusChange := self.onMyAudioFocusChange;

[DCC Error] uMain.pas(205): E2035 Not enough actual parameters

Comments are closed.