Search code examples
androidbroadcastreceiverandroid-serviceandroid-8.0-oreoandroid-intentservice

Android : Not able to sync data between applications above Oreo + devices


I am stuck on sync real time data between 2 app only in Oreo+ devices, Like if different user login to the app then it should be immediately effect in other app and It should also change in other app.(e.g. Facebook and Facebook Messenger. If you logout from Facebook, it will automatically logout from FB Messenger or If you log into Facebook then it will automatically logged into FB Messenger and vice versa) I created broadcast receiver in both app and if login changes from one app then send broadcast to other app where it will do rest of work.

I have googled on it and I found some ways.

I have read this document

https://developer.android.com/about/versions/oreo/background

  • We have published differently signed APKs so not able to provide same signature permission in receiver.

Already went through this links

Broadcast receiver not working in oreo

Oreo: Broadcast receiver Not working

Broadcast receiver registered in manifest not getting called in Android Oreo

Receiver stopped receiving in Oreo

Thought to implement this ways but..

1) Create foreground service and register receiver into it. - As this way, I need one notification which is required to run foreground service. and I can't do that.I can't show unnecessary notification.

2) Scheduled job: - I can't use it as I need to run service all time in background.

What I have tried so far:

1) Register receiver in Application class : This is not working after application is killed because context has been killed.

2) Registering receiver in FireBase Notification service, but it's only initialize when notification arrives.

Code:

Registering receiver in Application class

ASampleActionReceiver mASampleActionReceiver = new ASampleActionReceiver();
IntentFilter filterAction = new IntentFilter();
filterAction.addAction("com.sample.example.receiver.operation");
registerReceiver(mASampleActionReceiver, filterAction);

In Manifest

<receiver android:name=".receiver.ASampleActionReceiver">
        <intent-filter>
            <action android:name="com.sample.example.receiver.operation" />
        </intent-filter>
</receiver>

Intent service will start by receiver

<service
android:name="com.sample.example.services.SampleOperationService"
android:enabled="true"
android:exported="false" />

And a Receiver ASampleActionReceiver.java

    public class ASampleActionReceiver extends BroadcastReceiver {

    Context mContext;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;
        AdoddleLog.d("LOG", intent.getExtras().getString("loginData"));

        Intent mIntent = new Intent(mContext, SampleOperationService.class);
        mIntent.putExtras(intent);
        mContext.startService(mIntent);
    }
}

can some one please suggest better solution?

Can I use AIDL for app communication ? does it work if any one application is idle or not running in background ?


Solution

  • Finally, I found solution and I would like to post detailed answer.

    I used AIDL for sharing data between 2 Apps

    In Both app, Create AIDL file in same package name like com.common.app and create one aidl file in it.

    // IRemoteService.aidl
    package com.common.app;
    
    // Declare any non-default types here with import statements
    
    interface IRemoteService {
        void onReceive(String data);
    }
    

    In both app, Need to create intent-service SampleOperationService.java , it will do rest of work after data receiving from another app. you can use JobIntentService instead.

    public class SampleOperationService extends IntentService{
    
        private String DEBUG_LOG = "SampleOperationService";
    
        /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         */
        public SampleOperationService() {
            super("SampleOperationService Service");
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            //here you will get data in intent extra, in "data" key, Which is send from another app. You can do rest of work here
        }
    }
    

    In Both App, create services not require to add in same package like aidl. It contain one service binder, which extend AIDL Stub. here you will get data from the other application.

    public class RemoteService extends Service {
        @Override
        public IBinder onBind(Intent intent) {
            return (new RemoteServiceBinder());
        }
    
        private class RemoteServiceBinder extends IRemoteService.Stub {
            @Override
            public void onReceive(String data) {
                Intent mIntent = new Intent(RemoteService.this, SampleOperationService.class);
                mIntent.putExtra("data", data); // you will get data from the second app
                startService(mIntent);
            }
        }
    }
    

    Manifest.xml

    For first app

    <service
        android:name="com.firstapp.app.service.SampleOperationService"
        android:enabled="true"
        android:exported="false" />
    
    <service android:name="com.firstapp.app.RemoteService"> // this is service 
        <intent-filter>
             <action android:name="com.common.app.IRemoteService" />// this is the path of aidl file
         </intent-filter>
    </service>
    

    For second app

    <service
        android:name="com.secondapp.app.service.SampleOperationService"
        android:enabled="true"
        android:exported="false" />
    
    <service android:name="com.secondapp.app.RemoteService">
        <intent-filter>
             <action android:name="com.common.app.IRemoteService" />// this is the path of aidl file which will on same place for both app
         </intent-filter>
    </service>
    

    Data Passing:

    In Both app, We need to bind remote service.

    In case of Activity, bind service in onCreate

    public class SampleActivity extends AppCompatActivity implements ServiceConnection {
    
        private IRemoteService bindingRemoteService;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
            bindRemoteService();
        }
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bindingRemoteService = IRemoteService.Stub.asInterface(service);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            bindingRemoteService = null;
        }
    
        private void bindRemoteService() {
            Intent implicit = new Intent(IRemoteService.class.getName());
            List<ResolveInfo> matches = getPackageManager()
                    .queryIntentServices(implicit, 0);
            for (ResolveInfo mResolveInfo : matches) {
    
                if (mResolveInfo.serviceInfo.packageName.equalsIgnoreCase("com.secondapp.app")) {// for second app it will be "com.firstapp.app"
                    Intent explicit = new Intent(implicit);
                    ServiceInfo svcInfo = mResolveInfo.serviceInfo;
                    ComponentName cn = new ComponentName(svcInfo.applicationInfo.packageName,
                            svcInfo.name);
                    explicit.setComponent(cn);
                    getApplicationContext().bindService(explicit, this, Context.BIND_AUTO_CREATE);
                    break;
                }
            }
        }
    
    }
    

    Here just bind other app service. so it won't receive data in same app. and bind service to specific package for security purpose

    To send data to other app

    public void sendDataToOtherApp(){
        if (bindingRemoteService != null) {
            try {
                HashMap map = new HashMap();
                map.put("data", data);// data will be string
                bindingRemoteService.onReceive(new Gson().toJson(map));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    

    And data will receive in RemoteService of the other application.