I did some additional research and was able to find a satisfactory solution. Here it is:
The library should be designed so that every application that integrates it publishes a broadcast receiver with a known action, for example. com.mylib.ACTION_DETECT.
The library should have an additional service that publishes some AIDL interface, which helps to make a decision - if the current library instance can be activated. AIDL can have some useful methods, for example getVersion (), isActive (), getUUID ().
Decision template: if the current instance has a higher version number, the other will become active. If the current instance has a lower version, it deactivates itself or remains deactivated if it is already disabled. If the current instance has an equal version for another instance, then if the other instance is inactive and the other uuid library is lower (using the compareTo method), it activates itself. In another state, he deactivates himself. This cross-validation ensures that each library will make its own decision - there will be no ambiguous cases, because each library will extract the required data from the published AIDL service of other libary instances in other applications.
The next step is to prepare an IntentService, which is launched every time a new package is removed or added, or the library application is launched for the first time. IntentService requests all packets for broadcast receivers that implement com.mylib.ACTION_DETECT. It then iterates through the detected packages (rejecting its own package) and binds to the AIDL support of each other instance (the AIDL service class name will always be the same, only the application package will be different). After the binding is completed, we have a clear situation - if the result of applying the template is “positive” (our instance has a better version or a higher uuid or is already active), then this means that other cases considered themselves “negative” and deactivated themselves, Of course, The template should apply to each associated AIDL service.
I apologize for my poor English.
The work code is ConfictAvoidance: IntentService, which supports binding, so this is also the AIDL service mentioned above. There is also a BroadcastReceiver that runs conflict checking.
public class ConflictAvoidance extends IntentService { private static final String TAG = ConflictAvoidance.class.getSimpleName(); private static final String PREFERENCES = "mylib_sdk_prefs"; private static final int VERSION = 1; private static final String KEY_BOOLEAN_PRIME_CHECK_DONE = "key_bool_prime_check_done"; private static final String KEY_BOOLEAN_ACTIVE = "key_bool_active"; private static final String KEY_LONG_MUUID = "key_long_muuid"; private static final String KEY_LONG_LUUID = "key_long_luuid"; private WakeLock mWakeLock; private SharedPreferences mPrefs; public ConflictAvoidance() { super(TAG); } private final IRemoteSDK.Stub mBinder = new IRemoteSDK.Stub() { @Override public boolean isActive() throws RemoteException { return mPrefs.getBoolean(KEY_BOOLEAN_ACTIVE, false); } @Override public long[] getUUID() throws RemoteException { return getLongUUID(); } @Override public int getSdkVersion() throws RemoteException { return 1; } }; @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() {
AIDL File:
package com.mylib.android.sdk; interface IRemoteSDK { boolean isActive(); long[] getUUID(); int getSdkVersion(); }
Manifest example:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mylib.android.sdk" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="4" /> <service android:name="com.mylib.android.sdk.utils.ConflictAvoidance" android:exported="true" /> <receiver android:name="com.mylib.android.sdk.utils.ConflictAvoidance$DetectionReceiver" > <intent-filter> <action android:name="com.mylib.android.sdk.ACTION_DETECT_LIB" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <action android:name="android.intent.action.PACKAGE_REMOVED" /> <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" /> <action android:name="android.intent.action.PACKAGE_REPLACED" /> <data android:scheme="package" /> </intent-filter> </receiver> </application> </manifest>
Act:
<action android:name="com.mylib.android.sdk.ACTION_DETECT_LIB" />
This is a common action that is used to discover other applications in the library.
Using logs may seem odd, but I'm using a custom wrapper that supports formatting to reduce StringBuffers' debugging overhead.