Вопрос по sharedpreferences, android-context, android-intent, android – Как я могу поделиться файлом SharedPreferences между двумя разными приложениями для Android?
Я боролся с этим некоторое время. По сути, я хочу, чтобы два приложения (которые всегда будут устанавливаться вместе) совместно используют настройки, при этом одно из них является просто службой, которая работает в фоновом режиме и должна использовать настройки (должны иметь настройки, но толькоreally необходимо прочитать их), а другое приложение является интерфейсным приложением пользовательского интерфейса, которое должно иметь возможность записи в файл настроек, принадлежащий другому приложению. Служба будет работать в фоновом режиме (что может быть определено предпочтениями), а пользовательский интерфейс позволит пользователю редактировать предпочтения и просматривать некоторую информацию из службы. Однако это будут разные пакеты / приложения.
Я пытался следоватьэтот урок что дало мне довольно хорошее представление о том, как иметь предпочтения в одном приложении, которые могут быть прочитаны другим. По сути, я создаю новый контекст черезmyContext = createPackageContext("com.example.package",Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
а затем позвонитеmyContext.getSharedPreferences("pref_name", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
Однако я не могу успешно писать в настройки из внешнего приложения - (SharedPreferences.Editor) .commit () возвращает false, и в logcat появляется предупреждение о невозможности изменить pref_name.xml.bak.
Как я могу успешно настроить свои приложения, чтобы они оба могли читать и записывать в один и тот же файл настроек (который хранится в папке данных одного из них)?
я должен отметить, что это официально не поддерживается, хотя может существовать поддерживаемый способ сделать это (то есть это НЕ будет этот метод), добавленный в Android в будущем (источник для обоих утверждений: см. Второй абзацэта ссылка).
Again, this is unsupported and is very possibly unstable. I primarily did this as an experiment to see if it was possible; take extreme caution if you are planning to actually incorporate this method into an application.
Однако представляется возможным разделить предпочтения между приложениями, если выполняются несколько требований. , если вы хотите, чтобы приложение B могло иметь доступ к настройкам приложения A, имя пакета приложения B должно быть дочерним по отношению к имени пакета приложения A (например, приложение A:com.example.pkg
Приложение B:com.example.pkg.stuff
). Кроме того, они могут не захотеть получить доступ к файлу в одно и то же время (я предполагаю, что применяются те же правила, что и для доступа к ним между действиями, если вы хотите обеспечить атомарный доступ, вам придется использовать дополнительные меры защиты, такие как .wait ( ) и .notify (), но я не буду вдаваться в подробности).
Note: all of this works on the emulator on 2.2 and 2.3.3- I haven't extensively tested across devices or android versions.
Things to do in the app which is going to own the preferences (App A from above):
1.) Declare the SharedPreferences file
Это довольно просто. Просто объявите пару переменных для вашего файла sharedpreferences и редактора в вашем классе и создайте их экземпляр в вашем методе onCreate. Теперь в настройках можно указать строку, которую вы будете использовать, чтобы убедиться, что другое приложение может правильно ее прочитать.
public class stuff extends Activity {
SharedPreferences mPrefs = null;
SharedPreferences.Editor mEd= null;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPrefs = (getApplicationContext()).getSharedPreferences("svcprefs", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
mEd = mPrefs.edit();
mEd.putString("test", "original send from prefs owner");
mEd.commit();
2.) Set up the backup file Появляется метод getSharedPreferences, который проверяет наличие файла .bak для загрузки настроек. Вот почему в документации сказано, что он не будет работать в нескольких процессах; чтобы минимизировать ввод-вывод, он загружает префиксы ОДИН РАЗ, когда вы их захватываете, и создает резервные копии только при закрытии приложения / действия. Однако, если вы вызовете это из внешнего приложения, вы получите предупреждение о том, что у вас нет необходимых прав доступа к папке (которая является первой папкой данных приложения). Чтобы исправить это, мы собираемся сами создать файл .bak и сделать его доступным для чтения / записи. Я выбрал для этого три переменных в моем общем классе.
final String[] copyToBackup = { "dd", "if=/data/data/com.example.pkg/shared_prefs/prefs.xml", "of=/data/data/com.example.pkg/shared_prefs/prefs.xml.bak", "bs=1024" };
final String[] mainFixPerm = {"chmod", "666", "/data/data/com.example.pkg/shared_prefs/prefs.xml"};
final String[] bakFixPerm = {"chmod", "666", "/data/data/com.example.pkg/shared_prefs/prefs.xml.bak"};
и сделать функцию в моем основном классе, которая будет принимать их в качестве аргументов и выполнять их
public void execCommand(String[] arg0){
try {
final Process pr = Runtime.getRuntime().exec(arg0);
final int retval = pr.waitFor();
if ( retval != 0 ) {
System.err.println("Error:" + retval);
}
}
catch (Exception e) {}
}
Это не очень красиво или хорошо, но это работает. Теперь в вашем методе onCreate (сразу после editor.commit ()) вы будете вызывать эту функцию для каждой из трех строк.
execCommand(copyToBackup);
execCommand(mainFixPerm);
execCommand(bakFixPerm);
Это скопирует файл и сделает как основные .xml, так и .xml.bak файлы доступными для сторонних программ. Вы также должны вызвать эти три метода в вашем onDestroy (), чтобы убедиться, что резервная копия базы данных должным образом резервируется при выходе из вашего приложения, и дополнительно вызывать их прямо перед вызовом getSharedPreferences в другом месте вашего приложения (иначе он загрузит файл .bak, скорее всего устарел, если другой процесс редактировал основной XML-файл). Это все, что вам нужно сделать в этом приложении, хотя. Вы можете вызвать getSharedPreferences в другом месте этого действия, и оно будет извлекать все данные из XML-файла, что позволит вам затем вызвать методы getdatatype (& quot; ключ & quot;) и извлечь их.
Things to do in the accessing file(s) (App B from above)
1.) Write to the file
Это еще проще. Я сделал кнопку для этого действия и настроил код в его методе onClick, который сохранит что-то в файле общих настроек. Помните, что пакет App B должен быть дочерним по отношению к пакету App A. Мы будем создавать контекст на основе контекста приложения A, а затем вызывать getSharedPreferences для этого контекста.
prefsbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Context myContext = null;
try {
// App A's context
myContext = createPackageContext("com.example.pkg", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
} catch (NameNotFoundException e) {e.printStackTrace();}
testPrefs = myContext.getSharedPreferences("svcprefs", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
testEd = testPrefs.edit();
String valueFromPrefs = testPrefs.getString("test", "read failure");
TextView test1 = (TextView)findViewById(R.id.tvprefs);
test1.setText(valueFromPrefs);
testEd.putString("test2", "testback");
boolean edit_success = testEd.commit();
Это захватывает строку, которую я установил в другом приложении, и отображает ее (или сообщение об ошибке) в текстовом представлении в этом приложении. Кроме того, он устанавливает новую строку в файле настроек и фиксирует изменения. После этого, если ваше другое приложение вызывает getSharedPreferences, оно извлечет файл, включая изменения из этого приложения.
dd
или жеchmod
, На самом деле, это может быть даже возможно с помощью другой техники - и если это так, я надеюсь, что кто-то опубликует ответ. Это просто способ, которым я заставил это работать.
matt5784
ContentProvider
что поддерживается вашимSharedPreferences
.
писано с тем же набором сертификатов, чтобы поделиться этим файлом.
Установите sharedUserId в обоих приложениях одинаковым.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hello"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="com.example">
....
Получить контекст из другого пакета:
mContext = context.createPackageContext(
"com.example.otherapp",
Context.MODE_PRIVATE);
mPrefs = mContext.getSharedPreferences("sameFileNameHere", Activity.MODE_PRIVATE);
Получить элементы, как обычно, из SharedPreference. Вы можете получить к нему доступ сейчас.