Android AIDL learning (server)

Posted by murtoz on Thu, 18 Nov 2021 10:13:10 +0100

In the process of learning AIDL, I can't read many books and find a lot of information on the Internet. Finally, I can realize the call of AIDL. Here I write my understanding and implementation to facilitate the memo search.

The main reason is that their foundation is too poor, others write too tall, and they still can't understand a lot. Write it down in a way that you can see clearly.

If you don't say much, get back to the point.

What is AIDL

AIDL is an abbreviation and its full name is Android Interface Definition Language, that is, Android Interface Definition Language.

It can define an interface and provide it to other app calls.

Why do you need AIDL voice interface

Each app has its own independent process running in the virtual machine. The virtual machine divides an independent memory running space for each app. The app runs in this space and cannot cross the boundary.

It's good to have your own independent space. Programs run without affecting each other, but sometimes you can't complete the data you want to obtain. Only other apps can provide it, but you can't get out of the virtual machine. What should you do? At this time, AIDL comes. As long as the interfaces between apps are specified according to unified rules, they can transmit data through AIDL.

A (client) says that it wants to verify the login from B (server). If B returns success or failure, it can obtain an object from B.

Let's take this small requirement as a column to see how AIDL needs to be implemented.

First, let's look at the server. The server provides services. I'm the boss. All the rules are set by me. You are all younger brothers and must follow my rules.

Let's see how the server is implemented.

Environment: android stuido 3.6.2

Create a new project BService

Right click the app - > New - > Aidl - > Aidl file

  Name our new aidl file IMyBookManager.

  Create a class of Book.java. The class of Book must have the same namespace as that of IMyBookManager.

package com.example.bservice;

public class Book {
    private int price;
    private String name = "";

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

The Book class needs to be returned to the caller through the AIDL interface, so this class needs to be serialized.

We let him do it   Parcelable interface.

package com.example.bservice;

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {
    private int price;
    private String name = "";

    public Book(){}

    protected Book(Parcel in) {
        price = in.readInt();
        name = in.readString();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(price);
        dest.writeString(name);
    }
}

After processing the Book class, let's process our interface file    IMyBookManager

In the IMyBookManager.aidl interface file, we implement two interfaces, one is login, and the other is the class that returns a Book according to the Book name.

// IMyBookManager.aidl
package com.example.bservice;

// Declare any non-default types here with import statements
//All package names need to be imported.
import com.example.bservice.Book;

//It should be noted that the book we introduced is a serialized class.
parcelable Book;

interface IMyBookManager {
    /**
     * The basic type interface added by default can be deleted if not used
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    String login(String userName, String pwd);
    
    Book queryByName(String bookName);
}

  After processing the interface file, we compile it, press ctrl+f9, or click the menu to edit it.

After compilation, the system will automatically generate an implementation class, which is generated by the system and does not need our relationship. What we need to deal with is to implement a class and inherit the subclasses of the class generated by the system.

All right, let's add it now    MyBookManager inheritance    IMyBookManager.Stub class.

package com.example.bservice;

import android.os.RemoteException;

public class MyBookManager extends IMyBookManager.Stub {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
        
    }

    @Override
    public String login(String userName, String pwd) throws RemoteException {
        return null;
    }

    @Override
    public Book queryByName(String bookName) throws RemoteException {
        return null;
    }
}

  The above is a framework. Let's implement it briefly.

package com.example.bservice;

import android.os.RemoteException;

public class MyBookManager extends IMyBookManager.Stub {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

    }

    @Override
    public String login(String userName, String pwd) throws RemoteException {
        if(userName.equalsIgnoreCase("abcd") && pwd.equalsIgnoreCase("123")){
            return "success";
        }
        return "error";
    }

    @Override
    public Book queryByName(String bookName) throws RemoteException {
        Book book = new Book();
        book.setName(bookName);
        book.setPrice(100);
        return book;
    }
}

OK, so we have a simple implementation of the interface.

After talking so much, I still don't know how to use it. Now I'll talk about how to use it.

To provide external calls to other app s, we also need to create a service to provide external services through the binding method of the service.

All right, let's add a service.

Let's add a registration service first. The full path is com.example.bservice.service

  Generated code

package com.example.bservice.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

  Remember we just added an implementation class of MyBookManager, which integrates the subclass of IMyBookManager.Stub. Let me see what it looks like

We found that Stub is a class that integrates Binder. Let's take another look at Binder class

The Binder class implements the IBinder interface, and our Service also has a Bind method that returns the IBinder interface.

Then we can return our MyBookManager to the caller through this interface.

Finally, our MyService code returns our interface implementation class.

package com.example.bservice.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import com.example.bservice.MyBookManager;

public class MyService extends Service {
    
    MyBookManager bookManager = new MyBookManager();
    
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return bookManager;
    }
}

The implementation class of the interface has been completed and the service has been added. If our service wants to be called outside, we need to align and set it in the AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.bservice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".service.MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote"
            >
            <intent-filter>
                <action android:name="com.example.bservice.bookService"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 < Action Android: name = "com. Example. Bservice. Bookservice" / > is a call name defined for our service, which can be used arbitrarily. Of course, it should comply with the naming specification.

Our services can work normally everywhere and can provide external interface services.

Topics: Android