Android中App A向已关闭的App B发数据的方案咨询(无需检测B安装)
满足需求的Android跨应用数据传递方案
核心前提明确
你的需求核心是:A仅负责主动写入数据,无需感知B的存在/运行状态;B启动时能获取到A之前写入的数据(哪怕间隔数月);无B则数据自然丢弃。广播机制无法满足需求——Android 8.0及以上系统对静态注册的自定义广播有严格限制,无法唤醒未运行的App,且广播是一次性的,无法持久化到B启动时接收。
方案1:自定义Content Provider(推荐,安全持久)
这是Android官方推荐的跨应用数据共享方案,完全适配你的场景:
A侧实现
- 开发自定义Content Provider,实现
insert方法存储字符串数据(可基于SQLite或其他持久化存储):
public class DataShareProvider extends ContentProvider { public static final String AUTHORITY = "com.yourpackage.a.datashareprovider"; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/shared_data"); @Override public boolean onCreate() { // 初始化SQLite数据库或其他存储 return true; } @Override public Uri insert(Uri uri, ContentValues values) { // 将数据插入到存储介质,返回插入后的URI return CONTENT_URI; } }
- 在A的
AndroidManifest.xml中注册Provider,并声明自定义权限(和B开发者约定权限名称,确保只有B能访问):
<permission android:name="com.yourteam.permission.ACCESS_A_DATA" android:protectionLevel="signature" /> <!-- 签名级权限,仅约定App可访问 --> <provider android:name=".DataShareProvider" android:authorities="com.yourpackage.a.datashareprovider" android:exported="true" android:permission="com.yourteam.permission.ACCESS_A_DATA" />
- A发送数据时直接写入,无需任何B相关判断:
ContentValues values = new ContentValues(); values.put("data_content", "要传递的字符串内容"); getContentResolver().insert(DataShareProvider.CONTENT_URI, values);
B侧实现(由B开发者完成)
B启动时,通过约定的URI和权限查询数据:
Cursor cursor = getContentResolver().query( DataShareProvider.CONTENT_URI, null, null, null, null ); if (cursor != null) { while (cursor.moveToNext()) { String receivedData = cursor.getString(cursor.getColumnIndex("data_content")); // 处理数据逻辑 } cursor.close(); }
优势
- 数据持久化存储,只要A未卸载、未清理数据,哪怕间隔数月也能被B读取。
- 权限严格可控,避免第三方App窃取数据。
- A完全无需感知B的状态,只负责写入数据。
方案2:MediaStore公共存储(无需自定义组件)
利用系统公共存储实现无感知的数据共享:
A侧实现
将字符串写入公共存储的文本文件,Android 10+无需申请额外权限:
ContentValues values = new ContentValues(); values.put(MediaStore.Downloads.DISPLAY_NAME, "a_shared_data.txt"); values.put(MediaStore.Downloads.MIME_TYPE, "text/plain"); values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/A_SHARED"); Uri uri = getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) { outputStream.write("要传递的字符串内容".getBytes()); } catch (IOException e) { e.printStackTrace(); } }
B侧实现(由B开发者完成)
B启动时,查询MediaStore中约定路径/文件名的文件,读取内容后可删除文件避免重复读取。
注意点
- 公共存储的文件可能被用户手动清理,数据持久化可靠性不如Content Provider。
- Android 13+ B需要申请
READ_EXTERNAL_STORAGE权限。
方案3:FileProvider共享私有文件
通过FileProvider将A的私有文件共享给B:
A侧实现
- 配置FileProvider,在
AndroidManifest.xml中添加:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.yourpackage.a.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
- 在
res/xml/file_paths.xml中指定共享目录:
<paths> <files-path name="shared_files" path="shared/" /> </paths>
- 将字符串写入私有目录下的文件:
File sharedDir = new File(getFilesDir(), "shared"); if (!sharedDir.exists()) sharedDir.mkdirs(); File dataFile = new File(sharedDir, "a_data.txt"); try (FileWriter writer = new FileWriter(dataFile)) { writer.write("要传递的字符串内容"); } catch (IOException e) { e.printStackTrace(); }
B侧实现(由B开发者完成)
B启动时,通过约定的authority和文件名尝试访问共享文件:
try { Uri fileUri = FileProvider.getUriForFile(context, "com.yourpackage.a.fileprovider", new File(getFilesDir() + "/shared/a_data.txt")); try (InputStream inputStream = getContentResolver().openInputStream(fileUri)) { // 读取数据逻辑 } } catch (Exception e) { // 无B或文件不存在,直接忽略 }
注意点
- 需要双方严格约定文件名和FileProvider的authority。
- 私有文件不会被用户轻易清理,数据持久性较好,但权限配置相对繁琐。
内容的提问来源于stack exchange,提问作者SphericalCow
相关产品推荐
相关产品推荐

