Android盒子开发总结:基于6.0系统,关于刷到系统的app读取不到U盘文件的问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coder_Hcy/article/details/80590114

最近在做电视盒子,系统是6.0的,我负责的模块是更新模块。用的是增量更新,关于增量更新不多说,就是用阿里的工具。我负责的就是将下载的文件放到指定的目录(/cache/update.zip)下,这都是超级简单的。但更新的模块里有一个小功能就是U盘更新:就是遍历U盘的一级目录,找到指定的增量包(压缩文件),复制移动到指定目录下(/cache/update.zip)。这边的代码也超级简单,百度一大把。

4.4盒子(公司的旧盒子)一点问题没有,但6.0(公司的新盒子)就有问题,主要是读不了U盘的文件,file.listfile()==null,也就是遍历U盘的目录为空,期初以为是权限没动态获取,毕竟6.0,有些危险权限还是要尊重的。但核心论点来了。

1.我是不是可以认为,当盒子刷到系统里的时候,只要我在清单文件配置了权限,都不需要对这些权限做动态获取。

//从目前的调试结果看,我认为这一点应该是真命题。

2.是不是我动态获取了读写权限,我就可以在任意位置读写。

//我写过一个demo,运行在6.0的小米手机上,我就无法将文件写到/mnt下,但可以写到/mnt/sdcard下


这几天我遇到的问题是,当我这个app刷到系统的时候,监听到了U盘的热插拔,获得了U盘的路径,但遍历U盘的时候,listfile就是null,且就算我读取U盘的特定文件也会出错(权限有关的问题)。因为是刷到系统的,且我的清单文件也有读写权限,并且我事先在没刷盒子之前动态获取权限调试过是通过的,但一刷到系统(去除动态获取)就是有问题。所以我就认为是系统有问题,但系统那边又说他自己写过demo,在系统setting下编写从U盘copy文件到指定目录是没问题。


僵持不下,我就用了两种方案调试,

1.添加动态获取权限(读写)的代码,然后让系统打包刷机,测试是成功的但需要动态获取

2.将系统setting的权限都考到我的app清单文件下(我怀疑是少了某个权限),果不其然,测试成功。

总结:当app刷到系统目录下,是不需要动态获取权限的,但如果只有读写权限,是无法读到U盘上的文件的,至于需要的事哪个,我还没有找出,只能一锅端的全拿来。

 <!-- 系统升级权限 -->
    <uses-permission android:name="android.permission.REBOOT"/>
    <uses-permission android:name="android.permission.RECOVERY" />
    <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

   <!-- //系统设置的所有权限-->

    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
    <uses-permission android:name="android.permission.DEVICE_POWER" />
    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.HARDWARE_TEST" />
    <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.MASTER_CLEAR" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
    <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIMAX_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIMAX_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="com.android.certinstaller.INSTALL_AS_USER" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"/>
    <uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"/>
    <uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
    <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY"/>
    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
    <uses-permission android:name="android.permission.BATTERY_STATS"/>
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.MOVE_PACKAGE" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.BACKUP" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_STATS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.STATUS_BAR" />
    <uses-permission android:name="android.permission.MANAGE_USB" />
    <uses-permission android:name="android.permission.SET_POINTER_SPEED" />
    <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
    <uses-permission android:name="android.permission.COPY_PROTECTED_DATA" />
    <uses-permission android:name="android.permission.MANAGE_USERS" />
    <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
    <uses-permission android:name="android.permission.SET_TIME" />
    <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.REBOOT" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
    <uses-permission android:name="android.permission.READ_SEARCH_INDEXABLES" />
    <uses-permission android:name="android.permission.OEM_UNLOCK_STATE" />
    <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    <uses-permission android:name="android.permission.MANAGE_FINGERPRINT" />
    <uses-permission android:name="android.permission.USER_ACTIVITY" />
    <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
    <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
也许是这个盒子的6.0系统的原因,因为这个6.0版本是方案商公司的第一个6.0版本(又当小白鼠),也许是所有6.0以上都会有这个问题,今天积累下这个经验,让别人少走些弯路。


附件:U盘更新工具类

package com.familybox.model.businessImpl;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

import com.familybox.utils.Constants;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;

/**
 * @创建人:hcy
 * @创建时间:2018/5/31
 * @作用描述:Function:usb 更新工具类
 **/
public class UsbUpdateUtils {
    private Context context;

    public UsbUpdateUtils(Context context) {
        this.context = context;
    }


    public void usb_update(String current_apk_name) {
        //读取当前USB的路径
        SharedPreferences mSharedPreferences = context.getSharedPreferences("setting", Context.MODE_PRIVATE);
        String current_usb_path = mSharedPreferences.getString("usb_path", "none");
        //获取根目录
        File usbFile = new File(current_usb_path);
        if (usbFile != null && usbFile.exists()) {
            Log.i("UpdateApk>>>", "当前有U盘" + current_usb_path);
            Log.i("UpdateApk>>>", "开始遍历U盘的一级目录");
            if (usbUpdateListener != null) {
                usbUpdateListener.testtishi("当前有U盘" + current_usb_path);
                usbUpdateListener.testtishi("\n" + "开始遍历U盘的一级目录");
            }
            //查找更新文件
            File[] files = usbFile.listFiles();
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    Log.i("UpdateApk>>>", "U盘文件名:" + files[i].getAbsolutePath() + "???" + files[i].getName());
                    if (usbUpdateListener != null) {
                        usbUpdateListener.testtishi("\n" + "U盘文件名:" + files[i].getAbsolutePath() + "???" + files[i].getName());
                    }
                    File file = files[i];
                    if (file.getName().contains("update.zip")) {
                        Log.i("UpdateApk>?>", "找到要跟新的增量包:" + files[i].getName());
                        Log.i("UpdateApk>?>", "开始复制到指定目录:" + Constants.DOWN_FILE_DIR + "/" + Constants.UPDATE_FILE_NAME);
                        if (usbUpdateListener != null) {
                            Log.i("UpdateApk>>>", "找到要跟新的增量包:" + files[i].getName());
                            Log.i("UpdateApk>>>", "开始复制到指定目录");
                            usbUpdateListener.testtishi("\n" + "找到要跟新的增量包:" + files[i].getName());
                            usbUpdateListener.testtishi("\n" + "开始复制到指定目录");
                        }
                        Flowable.timer(2, TimeUnit.SECONDS)
                                .subscribeOn(Schedulers.io())
                                .subscribe((tag) -> {
                                    copyFileToSystem(file);
                                });
                        break;
                    }
                }
            } else {
                Log.i("UpdateApk>>>", "获取不到U盘的文件usbFile.listFiles()==null");
                if (usbUpdateListener != null) {
                    usbUpdateListener.testtishi("\n" + "获取不到U盘的文件usbFile.listFiles()==null");
                    usbUpdateListener.testtishi("\n" + "开始极端处理");
                    usbUpdateListener.testtishi("\n" + "获取" + current_usb_path + "/update.zip" + "文件");

                }
                File file = new File(current_usb_path + "/update.zip");
                if (file != null && file.exists()) {
                    if (usbUpdateListener != null) {
                        usbUpdateListener.testtishi("\n" + "该文件存在2秒后复制:" + current_usb_path + "/update.zip");
                    }
                    Flowable.timer(2, TimeUnit.SECONDS)
                            .subscribeOn(Schedulers.io())
                            .subscribe((tag) -> {
                                copyFileToSystem(file);
                            });
                } else {
                    if (usbUpdateListener != null) {
                        usbUpdateListener.testtishi("\n" + "文件不存在:" + current_usb_path + "/update.zip");
                    }
                }
            }
        } else {
            Log.i("UpdateApk>>>", "当前没有U盘" + current_usb_path);
            if (usbUpdateListener != null) {
                usbUpdateListener.usb_exist(false);
                usbUpdateListener.testtishi("当前没有U盘" + current_usb_path);
            }
        }
       /* SharedPreferences mSharedPreferences = context.getSharedPreferences("setting", Context.MODE_PRIVATE);
        String current_usb_path = mSharedPreferences.getString("usb_path", "none");

        if (usbFile != null && usbFile.exists()) {
            Log.i("UpdateApk>>>", "当前有U盘" + current_usb_path);
            Log.i("UpdateApk>>>", "开始遍历U盘的一级目录");
            if (usbUpdateListener != null) {
                usbUpdateListener.testtishi("当前有U盘" + current_usb_path);
                usbUpdateListener.testtishi("\n" + "开始遍历U盘的一级目录");
            }
            File[] files = usbFile.listFiles();
            for (int i = 0; i < files.length; i++) {
                Log.i("UpdateApk>>>", "U盘文件名:" + files[i].getAbsolutePath() + "???" + files[i].getName());

                if (usbUpdateListener != null) {
                    usbUpdateListener.testtishi("\n" + "U盘文件名:" + files[i].getAbsolutePath() + "???" + files[i].getName());
                }
                //  tv_tishi.setText(tv_tishi.getText() + "\n" + "U盘文件名:" + files[i].getAbsolutePath() + "???" + files[i].getName());
                File file = files[i];
                if (file.getName().contains("update.zip")) {
                    Log.i("UpdateApk>?>", "找到要跟新的增量包:" + files[i].getName());
                    Log.i("UpdateApk>?>", "开始复制到指定目录:" + Constants.UPDATE_APK_FILE_PATH);

                    if (usbUpdateListener != null) {
                        Log.i("UpdateApk>>>", "找到要跟新的增量包:" + files[i].getName());
                        Log.i("UpdateApk>>>", "开始复制到指定目录");
                        usbUpdateListener.testtishi("\n" + "找到要跟新的增量包:" + files[i].getName());
                        usbUpdateListener.testtishi("\n" + "开始复制到指定目录");
                    }
                    //  tv_tishi.setText(tv_tishi.getText() + "\n" + "找到要跟新的增量包:" + files[i].getName());
                    //  tv_tishi.setText(tv_tishi.getText() + "\n" + "开始复制到指定目录");
                    // tag = tv_tishi.getText().toString();
                    Flowable.timer(2, TimeUnit.SECONDS)
                            .subscribeOn(Schedulers.io())
                            .subscribe((tag) -> {
                                copyFileToSystem(file);
                            });
                    break;
                }
            }
        } else {
            if (usbUpdateListener != null) {
                usbUpdateListener.usb_exist(false);
                usbUpdateListener.testtishi("当前没有U盘" + current_usb_path);
            }
        }*/
       /* File file = new File(current_usb_path + "/update.zip");

        if (file != null && file.exists()) {
            Log.i("eee", "XXXX");
            Flowable.timer(2, TimeUnit.SECONDS)
                    .subscribeOn(Schedulers.io())
                    .subscribe((tag) -> {
                        copyFileToSystem(file);
                    });
        } else {
            Log.i("eee", "x2XXXX");
        }*/


    }


    /**
     * 复制文件的操作
     *
     * @param needCopyFile
     */
    private void copyFileToSystem(File needCopyFile) {
        InputStream inStream = null;
        FileOutputStream fs = null;
        try {
            int bytesum = 0;
            int byteread = 0;
            if (needCopyFile.exists()) { //需要复制的文件存在时
                inStream = new FileInputStream(needCopyFile.getAbsolutePath()); //读入原文件
                File targetDir = new File(Constants.DOWN_FILE_DIR + "/" + Constants.UPDATE_FILE_NAME);//目标文件
                Log.i("UpdateApk>>>", "复制单个文件" + targetDir.getAbsolutePath());
             /*   if (targetDir != null && !targetDir.exists()) {
                    targetDir.mkdirs();
                }*/
                targetDir.createNewFile();
                fs = new FileOutputStream(targetDir);

                // fs = new FileOutputStream(Constants.DOWN_FILE_DIR + "/" + Constants.UPDATE_FILE_NAME);
                byte[] buffer = new byte[1024];
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread; //字节数 文件大小
                    fs.write(buffer, 0, byteread);
                    if (usbUpdateListener != null) {
                        usbUpdateListener.usb_update_progress(bytesum, needCopyFile.length());
                    }
                }
                fs.flush();
            }
        } catch (Exception e) {
            Log.i("UpdateApk>>>", "复制单个文件操作出错" + e.getMessage());

            if (usbUpdateListener != null) {
                usbUpdateListener.copyAndMoveFailed("复制单个文件操作出错" + e.getMessage());

                usbUpdateListener.testtishi("\n" + "复制单个文件操作出错" + e.getMessage());
            }
            Log.i("复制单个文件操作出错", "复制单个文件操作出错" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public interface UsbUpdateListener {
        void usb_exist(boolean exist);

        void testtishi(String msg);

        void usb_update_progress(long current, long total);


        void copyAndMoveFailed(String msg);
    }

    private UsbUpdateListener usbUpdateListener;

    public void setUsbUpdateListener(UsbUpdateListener usbUpdateListener) {
        this.usbUpdateListener = usbUpdateListener;
    }


    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};

    public static void verifyStoragePermissions(Activity activity) {
        // Check if we have write permission
        int permission = ActivityCompat.checkSelfPermission(activity,
                Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE);
        }
    }


}
不好意思,扯了一堆废话,最后还是找到了原因。之所以/cache下写不进去,只要还是这个目录不具备相应写入权限。我看公司同事使用linux指令 chmod 777 打开这个权限就ok了。



猜你喜欢

转载自blog.csdn.net/Coder_Hcy/article/details/80590114