En primer lugar, debo tener en cuenta que esto no es oficialmente compatible, aunque puede haber una forma admitida de hacerlo (es decir, NO sería este método) agregado a Android en el futuro (fuente para ambas afirmaciones: ver segundo párrafo de this link).
De nuevo, esto no es compatible y es muy posiblemente inestable. Principalmente hice esto como un experimento para ver si era posible; tenga extrema precaución si planea incorporar este método en una aplicación.
Sin embargo, parece que es posible compartir preferencias entre las aplicaciones si se cumplen algunos requisitos. Primero, si desea que la aplicación B pueda acceder a las preferencias de la aplicación A, el nombre del paquete de la aplicación B debe ser hijo del nombre del paquete de la aplicación A (por ejemplo, aplicación A: com.example.pkg
, aplicación B: com.example.pkg.stuff
). Además, no pueden querer acceder al archivo al mismo tiempo (supongo que se aplican las mismas reglas que para acceder a ellos entre actividades, si desea garantizar el acceso atómico, deberá usar protecciones adicionales como .wait () y .notify(), pero no entraré en eso aquí).
Nota: todo esto funciona en el emulador en 2.2 y 2.3.3- No he probado exhaustivamente en dispositivos o versiones de Android.
Cosas que hacer en la aplicación que se va a poseer las preferencias (Ap A desde arriba):
1.) Declarar el archivo de SharedPreferences
Esto es bastante sencillo . Simplemente declare un par de variables para su archivo de preferencias compartidas y el editor de su clase y cree una instancia en su método onCreate. Puede poner una cadena en las preferencias ahora que usará para asegurarse de que la otra aplicación pueda leerla correctamente.
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.) Configurar el archivo de copia de seguridad El método getSharedPreferences aparece para comprobar si hay un archivo .bak para cargar las preferencias de.Es por eso que dice en la documentación que no funcionará en múltiples procesos; para minimizar la E/S, carga los prefs UNA VEZ cuando los agarra y solo los respalda cuando cierra su aplicación/actividad. Sin embargo, si llama a esto desde una aplicación externa, recibirá una advertencia acerca de no tener los permisos de archivo correctos para la carpeta (que es la carpeta de datos de la primera aplicación). Para solucionarlo, crearemos el archivo .bak nosotros mismos y lo haremos público/legible. La forma en que elegí hacer esto fue definir tres variables en mi clase general.
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"};
y hacer una función en mi clase principal que llevaría éstos como argumentos y ejecutarlos
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) {}
}
No es terriblemente bonita o buena, pero funciona. Ahora, en su método onCreate (justo después de editor.commit()) llamará a esta función con cada una de las tres cadenas.
execCommand(copyToBackup);
execCommand(mainFixPerm);
execCommand(bakFixPerm);
Esto copiará el archivo y hacer que tanto el .xml principal y los archivos .xml.bak accesibles a programas externos. También debe llamar a estos tres métodos en su onDestroy() para asegurarse de que la base de datos se respalda correctamente cuando se cierra su aplicación, y además llamarlos directamente antes de llamar a getSharedPreferences en otra parte de su aplicación (de lo contrario cargará el archivo .bak que es probable que esté desactualizado si otro proceso ha estado editando el archivo principal .xml). Sin embargo, eso es todo lo que necesitas hacer en esta aplicación. Puede llamar a getSharedPreferences en otra parte de esta actividad y tomará todos los datos del archivo .xml, lo que le permite llamar a los métodos getdatatype ("clave") y recuperarlos.
Cosas que hacer en el archivo (s) accede (Ap B desde arriba)
1.) escribir en el fichero
Esto es aún más simple. Inicié un botón en esta actividad y configuré el código en su método onClick que guardará algo en el archivo de preferencias compartidas. Recuerde que el paquete de la aplicación B debe ser un elemento secundario del paquete de la aplicación A. Crearemos un contexto basado en el contexto de la Aplicación A y luego llamaremos a getSharedPreferences en ese contexto.
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();
Esta agarra la cadena puse en la otra aplicación y la muestra (o un mensaje de error) en un TextView en esta aplicación. Además, establece una nueva cadena en el archivo de preferencias y confirma los cambios. Después de que esto se ejecute, si su otra aplicación llama a getSharedPreferences, recuperará el archivo, incluidos los cambios de esta aplicación.
¿Por qué, cuando dices que estos siempre se instalan juntos, tienen que ser dos aplicaciones diferentes? Parece un gran dolor de cabeza, por lo que presumiblemente está visualizando un beneficio, pero me pregunto si podría haber una forma de lograrlo sin tener aplicaciones separadas. –
Quería poder instalar ambas aplicaciones, configurar las preferencias y luego desinstalar la interfaz de usuario frontend pero dejar que el servicio continúe en segundo plano. Esto también me permite actualizar una aplicación sin volver a instalar ambas. Definitivamente no es necesario (y puede que ni siquiera lo use) pero fue una de mis ideas para implementar esto de la manera que lo diseñé. – matt5784