SkillAgentSearch skills...

Hermes

A smart, novel and easy-to-use framework for Android Inter-Process Communication (IPC). (简单易用的安卓进程间通信IPC框架)

Install / Use

/learn @Xiaofei-it/Hermes
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Hermes

A smart, novel and easy-to-use framework for Android Inter-Process Communication (IPC).

Chinese Readme 中文文档

Hermes is a smart, novel and easy-to-use framework for Android Inter-Process Communication (IPC). In this framework, you can use IPC even if you do not understand the underneath principle of Android IPC.

Please click HERE to see the demo.

Also, HermesEventBus is a Hermes-and-EventBus-based library which posts events between processes.

Note that maybe you will find that Hermes is still a little difficult to use. I have finished this library and promoted the performance. What to do for my next step is to simplify the usage, which will be released in version 0.7.0.

##Features

  1. Make method invocations over IPC so easy just like method invocations in a local process. The statements of method invocations are almost the same.

  2. Easy to use classes, singletons, utilities in another process.

  3. Support callbacks over IPC. You can provide the remote process with a callback to perform operations in the local process.

  4. Support GC over IPC. Hermes contains two garbage collectors to reclaim the instances created in the remote process and the local callbacks for remote processes.

##Principle

Since the main purpose of IPC is to invoke methods in another process, Hermes makes method invocation so easy that you can invoke methods in another process just like you invoke methods in a local process, and also, the statements of method invocation in another process are almost the same as the ones in a local process.

For example, the singleton pattern is always used in Android apps. Suppose an app contains two processes and they want to use a singleton. The singleton is as below:

@ClassId(“Singleton”)
public class Singleton {

    private static Singleton sInstance = null;

    private volatile String mData;

    private Singleton() {
        mData = new String();
    }

    public static synchronized Singleton getInstance() {
        if (sInstance == null) {
            sInstance = new Singleton();
        }
        return sInstance;
    }

    @MethodId(“setData”)
    public void setData(String data) {
        mData = data;
    }

    @MethodId(“getData”)
    public String getData() {
        return mData;
    }

}

Suppose the instance of Singleton is in Process A, and you want to access it from Process B. Then you write an interface as below:

@ClassId(“Singleton”)
public interface ISingleton {

    @MethodId(“setData”)
    void setData(String data);

    @MethodId(“getData”)
    String getData();

}

And the statements to access the singleton in Process B is as below:

//obtain the instance of Singleton
ISingleton singleton = Hermes.getInstance(ISingleton.class);

//Set a data
singleton.setData(“Hello, Hermes!”);

//Get the data
Log.v(TAG, singleton.getData());

Amazing, isn’t it?

Specifically, you pass an interface into Hermes.getInstance() and Hermes.getInstance() returns an instance which is exactly the same as the original one in Process A. Then when you invoke a method on the instance in Process B, the method is invoked on the same instance in Process A.

Now, how to write the interface? So easy. For example, there is a class named Foo in Process A, and you want to access it from Process B. Then you write an interface named IFoo and add into the interface the signatures of the methods which you want to invoke on Foo. Then add the same @ClassId annotation with the same value on IFoo and Foo, and add the same @MethodId annotation with the same value on the corresponding methods. Done! At this time, you can use Hermes.getInstance(IFoo.class) in Process B to get the instance of Foo in Process A.

##Gradle

dependencies {
    compile 'xiaofei.library:hermes:0.7.0'
}

##Maven

<dependency>
  <groupId>xiaofei.library</groupId>
  <artifactId>hermes</artifactId>
  <version>0.7.0</version>
  <type>pom</type>
</dependency>

##Usage

The following will tell you how to let the default process of the app to provide methods for other processes to invoke.

Hermes also allows method invocation between arbitrary processes. For more information about how to do this, please see HERE.

###AndroidManifest.xml

<service android:name="xiaofei.library.hermes.HermesService$HermesService0">
</service>

###Initialization

Always, an app has a default process in which most components run. Name this default process Process A.

Process A should initialize Hermes in Application.OnCreate() or Activity.OnCreate(), as the following does:

Hermes.init(getApplicationContext());

###Connection

Suppose there is another process, named Process B. Process B wants to invoke methods in Process A. Then Process B should initialize Hermes at the beginning.

You can do this in Application.OnCreate() or Activity.OnCreate() in Process B. The Corresponding API is Hermes.connect(Context). Before initialization, a HermesListener can be set to do some callbacks.

Hermes.connect(getApplicationContext());

You can call Hermes.isConnected() to see whether the process you are communicating with is still alive.

###Registration

In Process A, classes to be accessed by Process B should be registered before being accessed. There are two APIs to register classes: Hermes.register(Class<?>) and Hermes.register(Object). Hermes.register(object) is equivalent to Hermes.register(object.getClass()).

Registration is, however, not necessary if you do not add annotations on the classes. See Point 3 of Notice.

###Instance Creation

In Process B, there are three ways to create instances in Hermes: Hermes.newInstance(), Hermes.getInstance() and Hermes.getUtilityClass().

  1. Hermes.newInstance(Class<T>, Object...)

    This method creates an new instance of the specified class in Process A and returns the reference to the new instance. The second parameter will be passed into the corresponding constructor of the specified class.

    @ClassId(“LoadingTask”)
    public class LoadingTask {
    
        public LoadingTask(String path, boolean showImmediately) {
            //...
        }
    
        @MethodId(“start”)
        public void start() {
            //...
        }
    }
    
    @ClassId(“LoadingTask”)
    public class ILoadingTask {
        @MethodId(“start”)
        void start();
    }
    

    In Process B, you create the instance by Hermes.newInstance(ILoadingTask.class, “files/image.png”, true) to get the instance of LoadingTask.

  2. Hermes.getInstance(Class<T>, Object...)

    This method creates an new instance of the specified class through its static method named “getInstance” in Process A and returns the reference to the new instance. The second parameter will be passed into the corresponding static “getInstance” method of the specified class. This is useful when the specified class is a singleton.

    @ClassId(“BitmapWrapper”)
    public class BitmapWrapper {
    
        @GetInstance
        public static BitmapWrapper getInstance(String path) {
            //...
        }
    
        @GetInstance
        public static BitmapWrapper getInstance(int label) {
            //...
        }
    
        @MethodId(“show”)
        public void show() {
            //...
        }
    
    }
    
    @ClassId(“BitmapWrapper”)
    public class IBitmapWrapper {
    
        @MethodId(“show”)
        void show();
    
    }
    

    In Process B, you create the instance by Hermes.getInstance(IBitmapWrapper.class, “files/image.png”) or Hermes.getInstance(IBitmapWrapper.class, 1001) to get the instance of BitmapWrapper.

  3. Hermes.getUtilityClass(Class<T>)

    This method provides a way to use the utility class in another process. (This is very useful when developing plugins.)

    @ClassId(“Maths”)
    public class Maths {
    
        @MethodId(“plus”)
        public static int plus(int a, int b) {
           //...
        }
    
        @MethodId(“minus”)
        public static int minus(int a, int b) {
            //...
        }
    
    }
    
    
    @ClassId(“Maths”)
    public class IMaths {
    
        @MethodId(“plus”)
        int plus(int a, int b);
    
        @MethodId(“minus”)
        int minus(int a, int b);
    }
    

    In Process B, you can do as the below:

    IMaths maths = Hermes.getUtilityClass(IMaths.class);
    int sum = maths.plus(3, 5);
    int diff = maths.minus(3, 5);
    

##Notice

  1. Actually, if two processes are in separate apps, named App A and App B respectively, and App A wants to access a class in App B, and if the interface of App A and the corresponding class of App B has the same name and the same package name, then there is no need to add the @ClassId annotation on them. But pay more attention when you use ProGuard, since the names of the corresponding classes will be different after obfuscating.

  2. If the method in an interface and the method in the corresponding class have the same name, there is also no need to add the @MethodId annotation on them.

  3. If a class in Process A has a @ClassId annotation presented on it and its corresponding interface in Process B has also a @ClassId annotation with the same value presented on it, the class should be registered in Process A before being accessed by Process B. Otherwise, when Process B uses Hermes.newInstance(), Hermes.getInstance() or Hermes.getUtilityClass(), Hermes will not find the matching class in Process A. A class can be registered in its constructor or in Application.OnCreate().

    However, if the class and its corresponding interface do not have an annotation presented on them but have the same name and the same package name, then there is no need to register the class. Hermes finds the class according to the package and the name.

    The above also works when it comes to the method.

  4. If you want to prevent a class or a method from being accessed fr

View on GitHub
GitHub Stars1.3k
CategoryDevelopment
Updated7d ago
Forks193

Languages

Java

Security Score

80/100

Audited on Mar 31, 2026

No findings