New to Android development, I have made an app (the server) in Android Studio, and I have made a simple plugin in civTAK (client). To put simply, my app is proprietary, so I can’t expose or share the package/module of the app. So I came up with the solution to make a new library which will contain the aidl information, e.g., “aidlinterface” with the package name com.aidlinterface
, and then add that to the app level gradle for both server and client apps.
So the tree structure is project/server_app and project/aidlinterface and for the client project/client_app and project/aidlinterface. So, the app and the library are at the same hierarchy. Becuase of the this I was able to create the server and client packages to be the exact same “com.aidlInterface”. First question: is this approach ok for this problem/is this approach viable or is there a better way?
Second question, I have then made the service in the server app, and ensured that the service is initialised by going in the MainActivity.kt in the onCreate
function:
startService(Intent(this, ServiceName::class.java))
And for the purposes of this example we can say that the service only has a log statement that says “service initialised”, but when I go on logcat and filter by com.aidlinterface
, nothing is showing up, which tells me that the package is not attached. but I have added the package in:
dependencies {
implementation(project(":aidlInterface"))
...
}
Here is the AIDL interface:
// IAIDLColorInterface.aidl
package com.aidlinterface;
// Declare any non-default types here with import statements
interface IAIDLColorInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int getColor();
}
The same interface is present in the client app library.
Here is the service in the server app:
package com.aidlinterface;
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.Random;
public class AIDLColorService extends Service {
private static final String TAG ="AIDLColorService" ;
public AIDLColorService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return binder;
}
private final IAIDLColorInterface.Stub binder = new IAIDLColorInterface.Stub() {
@Override
public int getColor() throws RemoteException {
Random rnd = new Random();
int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
Log.d(TAG, "getColor: "+ color);
return color;
}
};
}
The manifest for the server app’s aidlInterface
library:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="@string/app_name"
android:supportsRtl="true">
<service
android:name=".AIDLColorService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="AIDLColorService" />
</intent-filter>
</service>
</application>
</manifest>
Here is the code from the client app where I am using this information:
<civTAK imports>
import com.aidlinterface.IAIDLColorInterface
class ColorPlugin(
mapView:MapView ){
private var AIDLColorService: IAIDLColorInterface? = null
private val serviceConnection = object: ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service:IBinder?){
AIDLColorService = IAIDLColorInterface.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName?){
AIDLColorService = null
}
init{
val serviceIntent = Intent("AIDLColorService")
serviceIntent.setPackage("com.aidlInterface")
pluginContext.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
override fun disposeImpl(){
pluginContext.unbindService(serviceConnection)
}
override fun onReceive(context:Context, intent: Intent){
// code for plugin
// CODE THAT CALLS SERVICE
b.setOnClickListener {
try {
val color = iADILColorService.color
it.setBackgroundColor(color)
} catch (e: RemoteException) {
// Handle exception
}
}
}
Any advice on this will be greatly appreciated. I understand this is a very vague problem, but I will try to answer any questions as best as possible!
6
Question 1: Is the Approach Viable?
Your approach to create a shared AIDL library (aidlinterface) that both the server and client applications can reference is a valid one. Here are some points to consider:
Shared AIDL Interface: Having a shared AIDL interface in a separate library helps maintain consistency and allows both apps to use the same interface without duplicating code. Make sure that all changes to the AIDL interface are reflected in both the server and client.
Package Naming: Using the same package name com.aidlinterface for both the service and the interface is appropriate, as it helps the Android framework recognize that they are related.
Dependencies: Ensure that the AIDL library is correctly added to both your server and client gradle files. Your usage of implementation(project(“:aidlInterface”)) in both projects is proper.
Service in Manifest: Make sure that your server app’s manifest properly declares the service. Ensure that the tag includes the correct package path if the service is not in the root package of the manifest.
In general, having an AIDL library is a good practice as it avoids code duplication and allows you to maintain a clean separation of concerns.
Question 2: Service Not Showing in Logcat
If the service is not logging anything and you can’t see logs from the AIDLColorService, there might be several issues to consider:
Service Initialization: Ensure that your service is being started correctly. In the MainActivity.kt, verify that the startService line is being executed as expected and the log statement in the service actually runs. You can add more log statements around it for debugging purposes.
Log Level: Ensure that you are filtering logcat correctly and that your filtering settings are inclusive of DEBUG logs. Sometimes, filtering by tag can lead to missing logs if the log level is set incorrectly.
Correct Intent Filter: In your service declaration within the manifest, check that the action specified in the intent filter (AIDLColorService) matches how you are starting the service. If using an action, the intent creation on the client side should contain the correct action.
Check for Errors: Look for any errors or exceptions in the Logcat output that might indicate issues with binding the service or starting it.
Correct Service Intent: When starting the service in the server application, ensure that the intent is set correctly. The correct way to reference the service would be as follows:
val serviceIntent = Intent(this, AIDLColorService::class.java)
startService(serviceIntent)
Running the Service: Double-check if your service is running. You can do this via Android Profiler or by looking for active services in your app through the developer options.
Client Side Binding
In your client code, ensure that the service name in the Intent matches the intent filter in the server’s manifest. You use an explicit intent for binding:
val serviceIntent = Intent(this, AIDLColorService::class.java)
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
If everything is configured properly, and the service is running, the onServiceConnected method should be triggered, and you’ll be able to call methods on the AIDL interface without issues.
Final Notes
If, after checking the above points, you’re still encountering issues, consider simplifying your setup to isolate the problem. You can create a simple test client and server within the same project to confirm the AIDL mechanism works before refactoring back to the library-based structure.
6