1. Gluon Attach
1.1. Overview
Attach addresses the integration with low-level platform APIs. Using Attach, you write code that accesses device and hardware features using a uniform, platform-independent API.
At runtime, the appropriate implementation (desktop, android, ios) makes sure the platform specific code is used to deliver the functionality.
The following sections provide a high-level overview of the current Attach features.
More information can be found in the Gluon website and you can find different samples using different Attach services.
This library is being actively extended, so if you think an important feature is missing, feel free to log an issue or contribute a pull request at our Attach repository.
1.2. General
The Attach project is split up into different services. Each service takes care of implementing a certain hardware or device feature, like access to general device information, information about the display, outputs of different sensors that are found on the device, etc.
The full list of services can be found here.
1.3. Using Attach
1.3.1. Prerequisites
Attach prerequisites are in line with those required by Gluon Client.
1.3.2. Adding Attach to the project
Configuring your project to include an Attach service is done via adding the dependency to the project and the name of the service to attachList
configuration.
When creating a project with the Gluon IDE plugin, the attachList
is already available
and pre-configured with the following four services: display, lifecycle, statusbar and storage.
The list of services can be extended with any of the available services.
For instance, the Position service, that allows accessing the device’s GPS, can be added as follows:
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>position</artifactId>
<version>${attach.version}</version>
</dependency>
...
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>client-maven-plugin</artifactId>
<version>${client.maven.plugin.version}</version>
<configuration>
<target>${client.target}</target>
<attachList>
...
<list>position</list>
</attachList>
<mainClass>${main.class}</mainClass>
</configuration>
</plugin>
1.3.3. Using Services
Each Attach service provides the functionality to access a given feature in every platform where it is supported.
Each service can be accessed via its create()
method, which returns an Optional
which contains an instance of the requested service.
The returned optional object might be empty if the runtime platform has no available implementation for that specific service.
PositionService positionService = PositionService.create().orElseThrow(() -> new RuntimeException("PositionService not available."));
positionService.positionProperty().addListener((obs, ov, nv) -> {
System.out.println("Latest known GPS coordinates from device: " + nv.getLatitude() + ", " + nv.getLongitude());
});
positionService.start();
Another useful class is the enum com.gluonhq.attach.util.Platform
, which provides an easy way to detect what
platform the application is currently running on: ANDROID
, IOS
or DESKTOP
.
1.4. Services Overview
For an overview of all the available services, we refer you to the services package overview page in the Attach javadoc:
1.4.1. Service Requirements
Each service has certain requirements that need to be addressed before deploying the mobile applications, either on Android, or on iOS, or both.
Attach javadoc provides detailed information on these cases.
Android
For instance, the Dialer service requires a CALL_PHONE
permission included in the Android manifest file:
<manifest ...>
<uses-permission android:name="android.permission.CALL_PHONE"/>
...
</manifest>
The AndroidManifest.xml
file is generated for the project with the client:package
goal, and it is available at target/client/aarch64-android/gensrc/android
.
The Client plugin takes care of most of these modifications, and usually, there is no need to modify this manifest.
Only in case you need to make any change, copy this file to src/android
and make any modification that might be needed. For every new run of client:package
, the manifest found at src/android
will be used.
iOS
For instance, the Position service requires a few keys included in the Default-Info.plist file:
<plist ...>
<dict>
...
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location services</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location services</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs bluetooth services</string>
</dict>
</plist>
The Default-Info.plist
file is generated for the project with the client:link
goal, and it is available at target/client/arm64-ios/gensrc/ios
.
In case you need to make any change, copy this file to src/ios
and make any modification that might be needed. For every new run of client:link
, the plist found at src/ios
will be used.
1.5. Attach source code
Attach is open source, and it is freely licensed under the GPL license. Its source code can be found under the Gluon Attach repository.
1.6. Building Attach
Note
|
The following sections are intended only for developers who want to create a native service or understand how the Attach native services are created. |
If you want to build Attach from code, you need JDK 11+, Xcode 11+, the Android SDK 29 and the Android NDK.
Clone the repository, and from Mac OS X, run:
export ANDROID_SDK=$ANDROID_HOME export ANDROID_NDK=$ANDROID_HOME/ndk-bundle ./gradlew clean build publishToMavenLocal
It will build all services for all possible platforms (desktop, iOS and Android), and it will install them to your .m2 local repository.
You can try to build from Linux or Windows, however the iOS implementation won’t be built.
Single service builds can be done as well. For instance, to build and install locally the Display service, run:
./gradlew :display:publishToMavenLocal
1.6.1. Platform builds
The tasks under mavenPublish.gradle
and native-build.gradle
perform the native build for desktop, iOS and Android.
The goal is to produce an artifact that can be used as dependency by the Client plugin when creating a native image that will be deployed to the target platform.
Such artifact (a jar file), bundles Java classes, configuration files and native libraries.
The builds are done with the nativeBuild
task. For instance, to build the native libraries for the three platforms, run:
./gradlew :display:nativeBuild
or in case you want to build a given platform, run:
./gradlew :display:iosBuild
Desktop
For a given service, its Java code (GraalVM) is compiled against JDK 11+, and with the desktopJar
task it is added to the ${service}-${version}-desktop.jar
file.
Reflection and jni configuration json files are added under META-INF/substrate/config
(see config files).
Native code, if present, will be compiled and the native library will be added to the jar to a native
folder.
iOS
For a given service, its Java code (GraalVM) is compiled against JDK 11+, and with the iosJar
task it is added to the ${service}-${version}-ios.jar
file.
Reflection and jni configuration json files are added under META-INF/substrate/config
(see config files).
Native code using Objective-C and found for each service under:
def osSources = [] osSources = "$projectDir/src/main/native/ios/${name}.m"
is compiled and linked, using the iOS SDK with certain flags and iOS frameworks, to create a native library under:
def linkerOutput = "$buildDir/native/ios/$arch/lib${name}.a"
The native library is then added to the jar to a native
folder.
Android
For a given service, its Java code (GraalVM) is compiled against JDK 11+, and with the androidJar
task it is added to the ${service}-${version}-android.jar
file.
Reflection and jni configuration json files are added under META-INF/substrate/config
(see config files).
Native code using C and found for each service under:
def nativeSourcesDir = [] nativeSourcesDir = "$projectDir/src/main/native/android/c/*.c"
is compiled and linked, using the Android SDK with certain flags, to create a native library under:
def linkerOutput = "$buildDir/native/android/lib${name}.a"
The native library is then added to the jar to a native
folder.
Finally, Java code for Android (Dalvik) is compiled against JDK 1.7, using the Android SDK. An Android library project is generated and bundled under META-INF/substrate/dalvik/${name}.aar
. It will contain mainly a jar with classes and an AndroidManifest.xml
file with the service requirements (like permissions or activities).
1.6.2. Attach with Client plugin
An Attach service is added to a project as regular dependency but it has also to be included in the attachList
:
<!-- dependencies -->
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.9</version>
</dependency>
<!-- plugin -->
<configuration>
<attachList>
<list>display</list>
</attachList>
</configuration>
If needed, the platform classifier can be used to run the project on HotSpot with the JavaFX Maven plugin:
<!-- dependencies -->
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.9</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.9</version>
<classifier>desktop</classifier>
<scope>runtime</scope>
</dependency>
This can be done with the Maven profiles, so these platform dependencies are only activated for the correct profile.
When running the Client plugin goals, for each Attach service, the plugin will apply the correct classifier based on the target and resolve the artifact.
Then, for every ${service}-${version}-${platform}.jar
file found in the classpath, the plugin will:
-
add the Java classes (GraalVM) to the native-image classpath to be compiled with
client:compile
, -
merge the configuration json files with others found in the classpath,
-
extract the native libraries into
target/client/$arch-$os/gvm/lib/lib${name}.a
, so they can be linked withclient:link
, -
and when targetting Android, extract the Android libraries (
.aar
) intotarget/client/$arch-$os/gvm/android_project/libs
. These libraries can be added as regular dependencies for the Android project when creating the apk in theclient:package
goal.
2. Gluon Attach JavaDoc
The Gluon Attach JavaDoc can be found here.