What is AIDL?
AIDL stands for Android Interface Definition Language. As the name says it’s an interface. It requires the using the Java Programming Language.
It is also requires a service to be able to use between applications.
What does it do?
AIDL allows for IPC(InterProcess Communication). Allowing for code to be accessible between different process, even different applications.
How do you create an AIDL file
- In Android Studio you would want to hover to your
app
package and right click and go into New.- You should be able to see a variety of different options, you will choose to AIDL.
- If it is not clickable
- Go to
build.gradle
on the module level and addaidl = true
buildFeatures { compose = true aidl = true }
- Now you should have a AIDL file created!
- Go to
- You will have to build your application to generate the Java files that you will be using to create the
Stub
, a type ofIBinder
, that you will use when you callonBind()
from client!
How do I use my AIDL Interface from a different application
Steps:
- Implement AIDL interface within a service class
- Add logic
- Update Service Side Manifest
- Permission
- Uses-Permission
- Service
- Add the same exact AIDL file into your client application
- Same package name and file contents
- Update Client Side Manifest
- Add
ServiceConnection
code to be able establish a connection with AIDL
1. Implement AIDL Interface within a service class
AIDL file
// IMyAidlInterface.aidl
package ramzi.eljabali.aidlmockapp;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters * and return values in AIDL. */
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(int x, int y);
String greet(String name);
}
Service implementing AIDL
package ramzi.eljabali.aidlmockapp
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
class MyAidlService : Service() {
override fun onBind(p0: Intent?): IBinder {
return binder
}
private val binder = object : IMyAidlInterface.Stub() {
override fun basicTypes(
anInt: Int,
aLong: Long,
aBoolean: Boolean,
aFloat: Float,
aDouble: Double,
aString: String?
) {
Log.i(
"IMyAidlInterface -> basicTypes()",
"AIDL supports the following types: Int, Long, Boolean, Float, Double, String."
)
}
override fun add(x: Int, y: Int): Int {
Log.i("IMyAidlInterface -> add()", "x value $x, y value $y, total ${x + y}")
return x + y
}
override fun greet(name: String?): String {
Log.i("IMyAidlInterface -> greet()", "hello $name, welcome to AIDL!")
return "Hello $name, welcome to AIDL!"
}
}
}
2. Update Service Side Manifest
What do you need to add?
<permission>
tag with the following propertiesandroid:name=
- `android:protectionLevel=
<uses-permission>
tag with the following propertiesandroid:name=
<service>
tag with the following propertiesandroid:name=
android:exported=
android:permission=
<intent-filter>
- A
<permission>
tag is used when you need to declare a security permission.- This security permission is what is used to limit what components or features applications can access.
- Within the
<permission>
tag we need to define the name(android:name
) of this permission and the protection level(android:protectionLevel
) for our application. android:name=ramzi.eljabali.aidlmockapp.permission.BIND_MY_AIDL_SERVICE
- In our case our permission will be a custom.
- I chose to go with the package name and the type of feature I am wanting to share.
- In our case our permission will be a custom.
android:protectionLevel:signature
signature
means that the system will only grant this permission if the requesting application is signed with same certificate as the application that declared the permission.
- A
<uses-permission>
tag specifies a system permission that you must grant for your application to operate correctly. This is granted upon installing your application(Android 5.1 and lower), or upon running your application(Android 6.0 and higher).android:name
property is used here to specify the permission name.- Could be defined within
<permission>
element, or a permission defined by another application, or just regular system permissions like"android.permission.CAMERA"
- Could be defined within
- A
<service>
tag is used to declare aService
subclass, as one of your applications components. Any service you have created within your application needs to be defined within your manifest using the<service>
tag otherwise, it will not be seen by the system and ultimately will not run.android:name
property is used to define whichService
subclass we are using within our application.- In this case it’s just
MyAidlService
android:name=".MyAidlService"
- In this case it’s just
android:exported
property is used to define whether components of other applications are allowed to use our service or interact with it.- In our case we do want other applications to be able to use our service so we will set
android:exported=true
, otherwise we would have set it tofalse
- In our case we do want other applications to be able to use our service so we will set
android:permission
property is used to define the name of a permission that an entity needs in order to launch the service or bind to it.- If a caller of
startService()
,bindService()
, orstopService()
hasn’t granted this permission, the method doesn’t work and theIntent
object isn’t delivered to the service. Client will need this permission in their manifest to be able to call on our service. android:permission="ramzi.eljabali.aidlmockapp.permission.BIND_MY_AIDL_SERVICE"
- If a caller of
- An
<intent-filter>
is required to be able to start this service. Because theintent-filter
specifies the type ofIntent
s that anActivity
,Service
, orBroadcast Reciever
can respond to.-
<action android:name="ramzi.eljabali.aidlmockapp.MyAidlService" />
-
Service Side AndroidManifest.xml
<permission
android:name="ramzi.eljabali.aidlmockapp.permission.BIND_MY_AIDL_SERVICE"
android:protectionLevel="signature" />
<uses-permission android:name="ramzi.eljabali.aidlmockapp.permission.BIND_MY_AIDL_SERVICE" />
<service
android:name=".MyAidlService"
android:exported="true"
android:permission="ramzi.eljabali.aidlmockapp.permission.BIND_MY_AIDL_SERVICE">
<intent-filter>
<action android:name="ramzi.eljabali.aidlmockapp.MyAidlService" />
</intent-filter>
</service>
3. Add the same exact AIDL file into your client application
- This acts as a contract between the applications that want to use this service.
In Android Studio you would want to hover to your app
package and right click and go into New.
1. You should be able to see a variety of different options, you will choose to AIDL.
2. If it is not clickable
1. Go to build.gradle
on the module level and add aidl = true
buildFeatures { compose = true aidl = true }
3. Now you should have a AIDL file created!
3. You will refactor the aidl package name to match the service side aidl package name.
1. In my case it was ramzi.eljabali.cientapplication
changed to ramzi.eljabali.aidlmockapp
to match with service side.
4. You will be build to generate the Java files necessary to be able to use the service.
4. Update Client Side Manifest
What do you need to add?
<uses-permission>
- As previously discussed
<uses-permission>
tag is required to specify the system permission we need to grant for our application to work. android:name
is the name of the permission we are wanting to grant.
- As previously discussed
<uses-permission android:name="ramzi.eljabali.aidlmockapp.permission.BIND_MY_AIDL_SERVICE" />
5. Connect to the Service
- Implement the
ServiceConnection
interface within your code to be able to know when you have connected to your service and when you have abruptly lost connection to your service.
Here’s how implementing the ServiceConnection
interface would look like:
private var iMyAidlInterface: IMyAidlInterface? = null
private var isBound = false
private val mConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
Log.i("Service-MainActivity", "Connection to service established")
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service)
isBound = true
}
override fun onServiceDisconnected(className: ComponentName) {
Log.e("Service-MainActivity", "Service has unexpectedly disconnected")
iMyAidlInterface = null
isBound = false
}
}
- You want to start the service and then bind to it.
- To start the service you will need to create an
Intent
- We previously discussed the use of the
<intent-filter>
within the service sideAndroidManifest.xml
- Now the
action
attribute within theIntent
we are creating needs to be that of theintent-filter
we previously defined on the service side. -
<action android:name="ramzi.eljabali.aidlmockapp.MyAidlService" />
val intent = Intent("ramzi.eljabali.aidlmockapp.MyAidlService")
- We then want to set the package name to the package name of the service.
intent.setPackage("ramzi.eljabali.aidlmockapp")
- We previously discussed the use of the
- To start the service you will need to create an
val intent = Intent("ramzi.eljabali.aidlmockapp.MyAidlService")
intent.setPackage("ramzi.eljabali.aidlmockapp")
- Now that we have created the
Intent
we can start the service. -startService(intent)
2. After Starting the service we want to bind to it. -bindService(intent, mConnection, BIND_AUTO_CREATE)
-BIND_AUTO_CREATE
is anInt
flag that specifies that it will automatically create the service as long as the binding exists.
startService(intent)
val isBinding = bindService(intent, mConnection, BIND_AUTO_CREATE)
Log.i("Service-MainActivity", "Binding service: $isBinding")
Log.i("Service-MainActivity", "Is bound to service: $isBound")
Putting it all together we get:
class MainActivity : ComponentActivity() {
private var iMyAidlInterface: IMyAidlInterface? = null
private var isBound = false
private val mConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
Log.i("Service-MainActivity", "Connection to service established")
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service)
isBound = true
}
override fun onServiceDisconnected(className: ComponentName) {
Log.e("Service-MainActivity", "Service has unexpectedly disconnected")
iMyAidlInterface = null
isBound = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val intent = Intent("ramzi.eljabali.aidlmockapp.MyAidlService")
intent.setPackage("ramzi.eljabali.aidlmockapp")
startService(intent)
val isBinding = bindService(intent, mConnection, BIND_AUTO_CREATE)
Log.i("Service-MainActivity", "Binding service: $isBinding")
Log.i("Service-MainActivity", "Is bound to service: $isBound")
setContent {
var greetingText by remember { mutableStateOf("Hello!") }
var mathText by remember { mutableStateOf("") }
ClientApplicationTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
innerPadding
Column(
Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = greetingText)
Button(onClick = {
if (isBound) {
greetingText = iMyAidlInterface?.greet("Ramzi") ?: "Couldn't call service"
mathText = iMyAidlInterface?.add(35, 7).toString()
} else {
greetingText = "Service not bound"
}
}) {
Text("Click me")
}
Text(text = mathText)
}
} } } }
override fun onDestroy() {
super.onDestroy()
if (isBound) {
unbindService(mConnection)
Log.i("Service-MainActivity", "Service unbound")
isBound = false
}
}
}
Results:
- You created an
AIDL
file - You implemented it as a service
- Added a custom
permission
to yourAndroidManifest.xml
- Added a custom
uses-permission
to yourAndroidManifest.xml
- Defined your
service
within yourAndroidManifest.xml
- Created an
intent-filter
to allow for it to be started
- Created an
- Client side we implemented the
ServiceConnection
interface to know when we have established a connection to the service and when it’s abruptly gone.override fun onServiceConnected()
override fun onServiceDisconnected()
- Client side created an
Intent
that would be used to start and bind the service - Client side started the service using
startService(intent)
- Client side was then bound to the service using
bindService(intent, mConnection, BIND_AUTO_CREATE)