Android:无法在 Oreo + 设备之上的应用程序之间同步数据
Android : Not able to sync data between applications above Oreo + devices
我卡在了仅在 Oreo+ 设备上同步 2 个应用程序之间的实时数据,就像如果不同的用户登录到该应用程序那么它应该立即在其他应用程序中生效并且它也应该在其他应用程序中发生变化。(例如 Facebook和 Facebook Messenger。如果你从 Facebook 注销,它会自动从 FB Messenger 注销,或者如果你登录 Facebook,它会自动登录 FB Messenger,反之亦然)我在两个应用程序中创建了广播接收器,如果登录从一个应用程序更改,那么将广播发送到其他应用程序,它将完成其余的工作。
我用谷歌搜索了一下,找到了一些方法。
我已阅读此文档
https://developer.android.com/about/versions/oreo/background
- 我们发布了不同签名的 APK,因此无法在接收器中提供相同的签名权限。
已经浏览过这个链接
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
想用这种方式实现但是..
1) 创建前台服务并将接收者注册到其中。
- 这样,我需要 运行 前台服务所需的一个通知。而且我做不到 that.I 无法显示不必要的通知。
2) 预定作业:
- 我无法使用它,因为我需要一直在后台 运行 服务。
目前我尝试过的:
1) 在应用程序中注册接收者 class :应用程序被终止后这不起作用,因为上下文已被终止。
2) 在 FireBase 通知服务中注册接收者,但它仅在通知到达时才初始化。
代码:
正在应用程序中注册接收器class
ASampleActionReceiver mASampleActionReceiver = new ASampleActionReceiver();
IntentFilter filterAction = new IntentFilter();
filterAction.addAction("com.sample.example.receiver.operation");
registerReceiver(mASampleActionReceiver, filterAction);
在清单中
<receiver android:name=".receiver.ASampleActionReceiver">
<intent-filter>
<action android:name="com.sample.example.receiver.operation" />
</intent-filter>
</receiver>
Intent 服务将由接收者启动
<service
android:name="com.sample.example.services.SampleOperationService"
android:enabled="true"
android:exported="false" />
和接收器 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);
}
}
有人可以提出更好的解决方案吗?
我可以使用 AIDL 进行应用通信吗?如果任何一个应用程序空闲或不在后台 运行 是否有效?
终于找到解决办法了,我想post详细解答。
我使用 AIDL 在 2 个应用程序之间共享数据
在这两个应用程序中,像com.common.app一样以相同的包名创建 AIDL 文件,并在其中创建一个 aidl 文件。
// IRemoteService.aidl
package com.common.app;
// Declare any non-default types here with import statements
interface IRemoteService {
void onReceive(String data);
}
在这两个应用程序中,需要创建 intent-service SampleOperationService.java ,它会在从另一个应用程序接收到数据后完成剩下的工作。您可以改用 JobIntentService。
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
}
}
在两个应用中,创建服务不需要像aidl一样添加到同一个包中。它包含一个服务绑定器,它扩展了 AIDL Stub。在这里您将从其他应用程序获取数据。
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
第一个应用程序
<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>
第二个应用
<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>
数据传递:
在两个应用中,我们需要绑定远程服务。
在Activity的情况下,在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
向其他应用发送数据
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();
}
}
}
并且数据将在其他应用程序的 RemoteService 中接收。
我卡在了仅在 Oreo+ 设备上同步 2 个应用程序之间的实时数据,就像如果不同的用户登录到该应用程序那么它应该立即在其他应用程序中生效并且它也应该在其他应用程序中发生变化。(例如 Facebook和 Facebook Messenger。如果你从 Facebook 注销,它会自动从 FB Messenger 注销,或者如果你登录 Facebook,它会自动登录 FB Messenger,反之亦然)我在两个应用程序中创建了广播接收器,如果登录从一个应用程序更改,那么将广播发送到其他应用程序,它将完成其余的工作。
我用谷歌搜索了一下,找到了一些方法。
我已阅读此文档
https://developer.android.com/about/versions/oreo/background
- 我们发布了不同签名的 APK,因此无法在接收器中提供相同的签名权限。
已经浏览过这个链接
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
想用这种方式实现但是..
1) 创建前台服务并将接收者注册到其中。 - 这样,我需要 运行 前台服务所需的一个通知。而且我做不到 that.I 无法显示不必要的通知。
2) 预定作业: - 我无法使用它,因为我需要一直在后台 运行 服务。
目前我尝试过的:
1) 在应用程序中注册接收者 class :应用程序被终止后这不起作用,因为上下文已被终止。
2) 在 FireBase 通知服务中注册接收者,但它仅在通知到达时才初始化。
代码:
正在应用程序中注册接收器class
ASampleActionReceiver mASampleActionReceiver = new ASampleActionReceiver();
IntentFilter filterAction = new IntentFilter();
filterAction.addAction("com.sample.example.receiver.operation");
registerReceiver(mASampleActionReceiver, filterAction);
在清单中
<receiver android:name=".receiver.ASampleActionReceiver">
<intent-filter>
<action android:name="com.sample.example.receiver.operation" />
</intent-filter>
</receiver>
Intent 服务将由接收者启动
<service
android:name="com.sample.example.services.SampleOperationService"
android:enabled="true"
android:exported="false" />
和接收器 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);
}
}
有人可以提出更好的解决方案吗?
我可以使用 AIDL 进行应用通信吗?如果任何一个应用程序空闲或不在后台 运行 是否有效?
终于找到解决办法了,我想post详细解答。
我使用 AIDL 在 2 个应用程序之间共享数据
在这两个应用程序中,像com.common.app一样以相同的包名创建 AIDL 文件,并在其中创建一个 aidl 文件。
// IRemoteService.aidl
package com.common.app;
// Declare any non-default types here with import statements
interface IRemoteService {
void onReceive(String data);
}
在这两个应用程序中,需要创建 intent-service SampleOperationService.java ,它会在从另一个应用程序接收到数据后完成剩下的工作。您可以改用 JobIntentService。
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
}
}
在两个应用中,创建服务不需要像aidl一样添加到同一个包中。它包含一个服务绑定器,它扩展了 AIDL Stub。在这里您将从其他应用程序获取数据。
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
第一个应用程序
<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>
第二个应用
<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>
数据传递:
在两个应用中,我们需要绑定远程服务。
在Activity的情况下,在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
向其他应用发送数据
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();
}
}
}
并且数据将在其他应用程序的 RemoteService 中接收。