Giới thiệu
Bài viết này minh họa cách đọc/ghi SharedPreferences của một ứng dụng khác thông qua cơ chế sharedUserId (cần cùng chữ ký ký ứng dụng). Lưu ý: Từ Android 10 (API 29), cơ chế này bị hạn chế nghiêm ngặt.
Yêu cầu tiên quyết
- Hai ứng dụng phải có cùng
android:sharedUserIdtrong Manifest - Hai ứng dụng phải được ký bằng cùng một keystore (cùng chữ ký)
- Ứng dụng đích phải dùng
Context.MODE_WORLD_READABLEhoặcMODE_WORLD_WRITEABLE(deprecated từ API 17)
Các bước thực hiện (Demo trong cùng 1 app)
Bước 1: Tạo dự án mới
Bước 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="Email"
android:inputType="textEmailAddress" />
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Name"
android:inputType="text" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:onClick="Save"
android:text="Save" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="Clear"
android:text="Clear Data" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="Retrieve"
android:text="Retrieve Data" />
</LinearLayout>
Bước 3: Code Java (src/MainActivity.java)
package app.com.sample;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etName, etEmail;
SharedPreferences sharedPreferences;
public static final String MY_PREFERENCE = "myPref";
public static final String KEY_NAME = "nameKey";
public static final String KEY_EMAIL = "emailKey";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etName = findViewById(R.id.etName);
etEmail = findViewById(R.id.etEmail);
// MODE_PRIVATE: Chỉ app này truy cập được (mặc định, an toàn)
// MODE_WORLD_READABLE/WRITEABLE: ĐÃ DEPRECATED, KHÔNG NÊN DÙNG
sharedPreferences = getSharedPreferences(MY_PREFERENCE, Context.MODE_PRIVATE);
loadSavedData();
}
private void loadSavedData() {
if (sharedPreferences.contains(KEY_NAME)) {
etName.setText(sharedPreferences.getString(KEY_NAME, ""));
}
if (sharedPreferences.contains(KEY_EMAIL)) {
etEmail.setText(sharedPreferences.getString(KEY_EMAIL, ""));
}
}
public void Clear(View view) {
etName.setText("");
etEmail.setText("");
Toast.makeText(this, "Cleared", Toast.LENGTH_LONG).show();
}
public void Retrieve(View view) {
loadSavedData();
Toast.makeText(this, "Retrieved", Toast.LENGTH_LONG).show();
}
public void Save(View view) {
String name = etName.getText().toString();
String email = etEmail.getText().toString();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_NAME, name);
editor.putString(KEY_EMAIL, email);
editor.apply(); // apply() async, commit() sync
Toast.makeText(this, "Saved", Toast.LENGTH_LONG).show();
}
}
Bước 4: Manifest (cần sharedUserId nếu muốn chia sẻ thực sự)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample"
android:sharedUserId="com.mycompany.shareduid"> <!-- Quan trọng -->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Cách truy cập SharedPreferences của app khác (nếu đủ điều kiện)
// Trong app B, muốn đọc SharedPreferences của app A
try {
Context otherAppContext = createPackageContext("com.app.a.package", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPref = otherAppContext.getSharedPreferences("pref_name", Context.MODE_PRIVATE);
String value = sharedPref.getString("key", "default");
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Giải pháp hiện đại thay thế
Do hạn chế bảo mật, Google khuyến nghị các phương án thay thế:
- ContentProvider: Chia sẻ dữ liệu có kiểm soát quyền truy cập
- DataStore (Jetpack): Thay thế SharedPreferences, hỗ trợ coroutine, type-safe
- File trong external storage: Chia sẻ qua file (cần quyền storage)
- WorkManager + BroadcastReceiver: Đồng bộ dữ liệu giữa apps
Chạy demo
Chạy app, nhập tên/email, nhấn Save. Thoát app và mở lại - dữ liệu vẫn còn (Retrieve). Nhấn Clear để xóa.
