修改Android手机的Preferences配置文件

本文介绍了如何在已root的Android设备上修改App的Preferences配置文件,包括使用Root Explorer直接编辑、编写App程序解析XML以及利用SDK的SharedPreferences方法。文章强调了修改时需注意的App状态、文件权限和缓存问题,提供了关键的Java命令行操作代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们的目的是修改Android手机中某app下的配置文件(至于为什么要修改这个配置文件呢? 你猜呀!)

即 /data/data/{package_name}/shared_prefs/{xxx}.xml文件

附:

{package_name} 为某App的包名

{xxx}为某个配置文件


修改步骤:

1. 你得把手机root

2. 下载Root Explorer,定位到上面那个路径下修改即可。

(完了, xxx  不要打偶! T_T……)


实际上,由于手机屏幕略小,如果需要经常的修改文件,在软键盘上敲下一长串无意义的文件,非常非常滴不方便的说。

即使,像哥一样聪明的知道,通过把资料才电脑发送到手机QQ上,再复制到剪贴板,然后粘贴到Root Explorer打开的配置文件里,省去了手动敲的步骤了。

但是,但是每次用食指或大拇指小心翼翼的定位光标还是十分痛苦的说。如果在修改的部分附近,即使多删去一些字符也无妨,拷贝之后,再手动打回来,也比拼人品刚好定位到好。

另外一种同步文字到手机上的方法:浏览器打开notepad.cc/xxx, 把文字拷贝进去,然后用Android手机的浏览器访问这个路径即可。

后缀xxx自定义,尽量独特一些好记一些,毕竟这也是要手敲的。。。


第二种方法, 既然配置文件是XML文件,自己去写个App程序解析不就可以了吗。

对头,虽然Java有好几种方法解析XML文件的方法,但是哥懒呀!(别打头。。。)


第三种方法,看好,要放大招了。

因为Android SDK提供了读写自家App内置配置文件的方法,好像是getSharedPreferences({xxx}, MODE_PRIVATE),

那么可不可以利用这个方法呢??

为了安全,SDK并未提供可以直接访问其他App的配置文件的方法(CreatePackageContext 和 shareUserId 使用颇多限制),

所以我们可以这样做: 

把要修改的配置文件拷贝到咱自己写的App的配置文件目录下,修改后再拷贝回去。 :)

当然前提是必须先root,(葵花宝典里不是说,欲练此功,必先自宫……)root不是阉割,而像开启了潜能,获得了强大力量,控制不好可能会误伤而已。


但是(“但是”,就意味着有问题呀)

其1,注意修改的时候最好把原App先退出,不然可能不会成功的。

举个例子:

假如App启动的时候调用了getSharedPreferences方法读取了配置文件,然后咱用Root Explorer去手动修改了这个配置文件的内容,如果App之后有写入配置文件的操作,会覆盖咱修改的内容的。

原因是SharedPreferences第一次读配置文件的时候,有个缓存在内存中,之后不会再去读这个配置文件的内容了,即使手动修改文件内容也不会反应到内存中。(纯属个人推测)


但是其2 注意文件权限,特别是所有者权限,读写执行权限倒无所谓。

不同的App安装时获得临时的不同的userId,如果拷贝之后,不是当前用户的所有者,用getSharedPreferences方法保存之后实际会生成一个新的文件,并不包含原来拷贝过来的文件的内容。

所以,实际步骤是:

拷贝原文件过来,然后修改目标文件的所有者为目标userId,修改内容,完毕后,再将文件拷贝回去,同样要把权限修改回去。

操作是用Java调用系统(Linux)命令来实现的。


关键代码如下:

拷贝文件的方法:

cp -f src srcBak   先拷贝一个临时文件

chown  destUid:destUid srcBak 修改临时文件的所有者为目标文件的所有者, uid和gid默认是一样的

cp -pf  srcBak dest  直接覆盖目标文件

至于uid的获取:使用Utils.getFileUid(),将配置文件所在的目录(/data/data/{package_name}/shared_prefs)传进去就可以获得了。

    private boolean copy(String src, String dest, String destUid) {

        if(!new File(src).exists()){
            return false;
        }

        String srcBak = src + "_bak";
        List<String> cmdList = new ArrayList<>();
        cmdList.add("cp -f " + src + " " + srcBak);
        cmdList.add("chown " + destUid +":" + destUid +" " + srcBak);
        cmdList.add("cp -pf " + srcBak + " " + dest);

        if(Utils.runSu(cmdList, null)){
            return true;
        }

        return false;

    }


工具文件:


public class Utils {

    private static final String TAG = "Utils";
    private static Context mContext;
    public static final String DEFAULT_SU = "/system/xbin/su";

    public static boolean isInitialized = false;
   /**
     * execute a common system command
     *
     * @param cmd
     */
    public static void run(String cmd) {
        Runtime runtime = Runtime.getRuntime();
        Process process = null;
        try {
            process = runtime.exec(cmd);
            process.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    /**
     * Get a result from inputstream
     *
     * @param in
     * @return
     */
    private static String getResult(InputStream in) {
        if (in == null) {
            return "";
        }

        byte[] bytes = new byte[1024];
        StringBuffer sb = new StringBuffer();
        try {
            while (in.read(bytes) != -1) {
                sb.append(new String(bytes));
            }
            return sb.toString();

        } catch (IOException e) {
            e.printStackTrace();
            return "";
        } finally {

            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * Execute a system command with root permission
     *
     * @param cmdList
     */
    public static boolean runSu(List<String> cmdList, CmdResult result) {
        return runSu(cmdList, DEFAULT_SU, result);
    }

    public static boolean runSu(List<String> cmdList, String suPath, CmdResult result) {

        File suFile = new File(suPath);
        if (!suFile.exists()) {
            showToast("Have your phone been rooted?\nSu not exits: " + suPath, Toast.LENGTH_LONG);
            Log.w(TAG, "su not exists: " + suPath);
            return false;
        }
        if (!suFile.canExecute()) {
            Log.w(TAG, "su can not be executed: " + suPath);
            return false;
        }
        if (cmdList == null || cmdList.size() == 0) {
            return false;
        }


        Runtime runtime = Runtime.getRuntime();
        Process process = null;
        long startStamp = System.currentTimeMillis();
        try {
            process = runtime.exec(suPath);

            DataOutputStream os = new DataOutputStream(process.getOutputStream());
            for (String cmd : cmdList) {
                if (!cmd.endsWith("\n")) {
                    cmd += "\n";
                }
                os.writeBytes(cmd);
                Log.d(TAG, "su cmd: " + cmd);
            }
            os.writeBytes("exit\n");
            os.flush();
            os.close();

            InputStream in = process.getInputStream();
            in = (in!=null) ? in : process.getErrorStream();

            if (result!=null) {
                result.retStr = getResult(in);
                result.ret = true;
                Log.d(TAG, "su result: " + result.retStr);
            }
            if(process.waitFor() == 0){
                return true;
            }else {
                // cost too much time, check su
                if(System.currentTimeMillis() - startStamp > 3*1000) {
                    if(mContext != null) {
                        Toast.makeText(mContext, "Have your phone been rooted?", Toast.LENGTH_LONG).show();
                    }
                }
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Get a file owner's id
     * @param path
     * @return
     */
    public static String getFileUid(String path) {

        File file = new File(path);
        if (!file.exists()) {
            return "";
        }
        List<String> cmdList = new ArrayList<String>();
        if(file.isDirectory()){
            cmdList.add("ls -ld " + path);
        }else {
            cmdList.add("ls -l " + path);
        }
        CmdResult cmdResult = new CmdResult();
        if( runSu(cmdList, cmdResult) ){
            if (cmdResult.ret) {
                String result =  cmdResult.retStr;
                String[] resArr = result.split(" ");
                if (resArr.length > 1 && !"".equals(resArr[1])) {
                    return resArr[1];
                }
            }
        }

        return "";
    }

    public static void showToast(String text , int duration) {
        if(mContext != null){
            Toast.makeText(mContext, text, duration).show();
        }
    }
}

public class CmdResult {

    public boolean ret;
    public String retStr;
}


Over!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值