Calling native Android APIs

Calling into the Android OS to utilize an API can be done in one of two ways. If you simply need to call an API that does not directly involve any parts of the Xojo framework, you can make a direct API call. If instead your API call will be interacting with a Xojo framework object, then it's best to create the declare as part of an extension method for the Xojo framework class with which you intend to use it.

Direct API call

Calling an Android OS API directly via a declare is no different than it would be for other operating systems.

For example, if to get the version number of Android upon which the app is running, the Android Developer documentation for the Build object indicates that it is located in the android.os library. The Release property holds the user-visible string and is accessed via the Alias section. Because Release is a string, the return value must be defined in the declare as a CString.

Declare Function AndroidVersion Lib "android.os.Build.VERSION" Alias "RELEASE" As CString

An example project that uses this declare is available at Platform > Android > Declare > Declare project.

Using Xojo framework classes

For Android, Xojo supports a special new declare format that allows making calls directly against certain objects and controls. This is useful when creating a Declare to change the property of a control. As an example, let's set the background color of a MobileButton.

The typical way to use this new type of Object Declare is by adding an Extends method to a Xojo Module in your project. To extend the MobileButton class with the ability to change its color, add a method called SetBackgroundColor with the following parameters: Extends ctrl As MobileButton, c As Color to a Xojo Module in your project.

In the Android developer documentation you will see that a Button is considered a View and thus has a setBackgroundColor method.

An Alias is not needed in this case since the extension method is what will be called in Xojo code. What you will do instead is make the Declare like this:

Declare Sub setBackgroundColor Lib "Object:ctrl:MobileButton" (myColor As Integer)

Breaking this down, it is calling the setBackgroundColor function. The Lib denotes this new type of Object declare: an Object, separated by a colon, the Xojo name of the object (in this case, the ctrl parameter from the extension method signature), followed by another colon, followed by the parameter's Xojo framework class name.

The next and final line of the extension method will call the declared function:

setBackgroundColor(c.ToInteger)

You can see this declare and its helper method in action from the Examples section of Xojo in the Platforms > Android > Declare > ButtonBackgroundColor project.

Declare integer types

The size-specific Integer types are now precise when used with Declares. The mappings are as follows:

Xojo Type

Kotlin Type

Int8, Byte

Byte

UInt8

UByte

Int16

Short

UInt16

UShort

Int32

Int

UInt32

UInt

Integer, Int64

Long

UInteger, UInt64

ULong

When mapping to Android API functions or Library functions, be sure to use the correct Xojo type that matches what is expected on Android. By far you will use Int32 and Integer.

Note

If you previously created Declares, you will likely need to change usage of Integer to Int32 as the mapping for that have changed compared to prior versions.

Nullable types

Xojo object variables (also properties, parameters and return values) can be Nil. With Kotlin, the default is that these things cannot be null (the equivalent of Nil). To ensure that you do not get compile errors with your parameters, declare them as nullable in Kotlin by appending the ? to the end of the type name.

Application context

Many Android APIs require the application context. This is not available in a Library so it has to be supplied by the app itself. There is a property for this:

MobileApplication.AndroidContextHandle As Ptr

You can pass this value to a function on the Library that then either saves it or uses it directly.

Using Ptr

Xojo uses the Ptr type to interface with Declares, however Kotlin does not have a Ptr type. Instead the Any type is used with Kotlin. This means that if you are passing something that is a Ptr to Kotlin (such as the app context above), your library function declaration should use Any? as the type of the parameter.

In your function, cast the parameter to the actual type you want. The same rule applies to return values. If the return value in the Declare is a Ptr, then in Kotlin the function declaration should be Any?.

You can also use Ptr with API calls to save object references as described below.

Library permissions

Depending on the API you are using, you may need to add permissions to the app manifest.xml for the Library. These permissions also need to be applied to the main app. This can be done using the Advanced tab of the Android Build Settings. There you will find the Permissions property in the Inspector where you can add one Permission per line.

Note

Previous versions let you separate permissions by spaces or commas. Going forward, each permission must be on its own line. Empty lines are ignored.

There you can add the permission constants that are required by your Library. In addition, you can follow the constant with additional attributes and they will also be applied to the app's manifest file.

For example, to include the android:maxSdkVersion attribute with the BLUETOOTH permission:

android.permission.BLUETOOTH android:maxSdkVersion="30"

Library dependencies

Similarly to permissions, your Library may make use of additional dependencies, which could even be other Libraries. These are added to the build.gradle file for the Library, but also need to be included in the main app.

You can add these dependencies using the Dependencies property on the Advanced Android Build Settings.

Creating objects

Previous versions of Xojo only let you call Companion (essentially shared) methods on Library classes. Now you can also work with class instances and call instance methods. This gives you even better control and ability to interface with Android APIs.

To create an object, your Library class should have a factory method on the Companion that returns a new instance. It is clearest to use create() as this method name.

In Xojo you create a Declare to this create() method and call it, saving the result in a Ptr.

Declare Function create Lib "com.example.utility.counter" () As Ptr
Var counter As Ptr = create

Instead of using a shared factory method, you can also call the Class constructor using this syntax:

Declare Function counter Lib "com.example.utility.counter" () As Ptr

Because the function name has the same name as the class itself, this will call the constructor of the class.

When you want to call a method on the instance, you pass the instance as a Ptr. First, Declare to the method adding “.instance” to the library location to indicate you are calling a class instance.

Declare Function increment Lib "com.example.utility.counter.instance" (ref As Ptr) As Integer

Then you can call the method and save its value.

Var count As Integer = increment(counter)

The reference as the Ptr must be the first parameter passed in the Declare. Follow it with other parameters as usual.

You can also call instance methods directly in the Android API in this manner.

Method callbacks

There are Android APIs that use callbacks to methods that you provide. In Xojo these methods are Delegates and are methods that you supply using AddressOf. It is very important that the signature of this method exactly matches what the callback expects which means you will be limited to just the Boolean and Ptr types.

If you want to use an API that uses its own callbacks, you will be better served by creating a Library and having the API do the callback to your own Library methods, which you can then call back to your Xojo methods.

You can pass the reference to the Xojo method using AddressOf like this:

Var cb As Ptr = AddressOf TestCallback
Declare Sub xojocallback Lib "com.example.utility.callback" (cb As Ptr)
xojocallback(cb)

The Xojo method can only use parameter types of Boolean and Ptr. It looks like this:

Public Sub TestCallback(b As Boolean, i As Ptr, s As Ptr)

In the Kotlin library you have to cast the incoming parameter to a function reference. This is a two-step process where you verify the function has the correct number of parameters and then you cast it to the specific parameter types. Sample code:

if (cb is Function3<*, *, *, *>) {
    try {
         (cb as Function3<Boolean, Long, String, Unit>).invoke(true, 42, "Hello")
         println("Sent callback to Xojo")
    } catch (e: ClassCastException) {
         println("Casting failed: ${e.message}")
    }
}

The Function3 indicates a function with 3 parameters (the last * indicates the return type), but you can change that as needed using Function1, Function2, etc. You can pass anything back through a Ptr type, but the Xojo code has to convert them using Ptr methods so you should not change the types of the values you send back to be different than what your Xojo code expects.

Object declares

Object Declares are not new, but for completeness are described here. Essentially an Object Declare uses special syntax to Declare to a UI control.

The typical way to use an Object Declare is by adding an Extends method to a Module. For example, an extension method to allow MobileButton to change its colors could look like this:

SetBackColor(Extends ctrl As MobileButton, c As Color)

The Object Declare looks like this:

Declare Sub setBackgroundColor Lib "Object:ctrl:MobileButton" (myColor As Int32)
setBackgroundColor(c.ToInteger)

Breaking this down, we are calling the setBackgroundColor function. The Lib denotes this new type of Object declare: an Object, separated by a colon, the Xojo name of the object (in this case, our ctrl parameter), followed by another colon, and the Xojo type of the object.

Kotlin declares

You can use the Android-specific Kotlin Declare designation to indicates that what is specified in the Alias section of the Declare should be used as is. This is particularly helpful when you want to cast Ptr values to a specific type for use with OS APIs.

This code gets a ColorStateList object for a Xojo Color value:

Var c As Color = Color.Blue

Declare Function valueOf Lib "android.content.res.ColorStateList:Kotlin" Alias _
"android.content.res.ColorStateList.valueOf(android.graphics.Color.argb(alpha.toInt(), r.toInt(), g.toInt(), b.toInt()))" _
(alpha As Int32, r As Int32, g As Int32, b As Int32) As Ptr

Var csl As Ptr = valueOf(255 - c.Alpha, c.Red, c.Green, c.Blue)

This code can then be used to call setStrokeColor on a MobileButton:

Declare Sub import Lib "android.content.res.ColorStateList:Import" // Imports the ColorStateList class

Declare Sub setStrokeColor Lib "Object:ctrl:MobileDateTimePicker:Kotlin" Alias "setStrokeColor(strokecolor as ColorStateList)" (strokeColor As Ptr)
setStrokeColor(csl)

As you can see, in the Alias is the Kotlin method call that casts the incoming Ptr value to a ColorStateList.

Import

Note the import declare in the code snippet above. This is also specific to Android. This Declare indicates that a specific class should be imported so that it can be used for casting purposes. If you left off that import, then the cast to ColorStateList would cause a compile error because ColorStateList would not be known.

You only need to import a specific class once. After you have done so it can be referenced by any other Declare, even ones in different methods.

The use of an import Declare is optional and is meant to simply the Kotlin method call code in the Alias. Instead of using import you can specify the full class path in the cast like this:

Declare Sub setStrokeColor Lib "Object:ctrl:MobileDateTimePicker:Kotlin" Alias "setStrokeColor(strokecolor as android.content.res.ColorStateList)" (strokeColor As Ptr)
setStrokeColor(csl)

Handles

Many classes in the framework now have Handle properties (or methods) which you can use with various Declare techniques described above. These include: FolderItem, Font, GraphicsPath, Locale, TimeZone, Graphics, Picture. In addition, the mobile controls have Handle properties that can serve as an alternative for an Object Declare.

Example project

You can download an example project that demonstrates a library and some of the concepts described above. You can use this as a template or starting point for creating your own libraries or Declares.

You might also want to take a look at the Android Design Extensions open source project, which has hundreds of Declares that can enhance your Android apps.