指定目录存放一个apk下载
我们这次把某个apk放在storage下的一个目录下,用一个FileProvider生成uri后,启动一个活动去安装。
首先用apk所在的path生成一个uri。
String external_path = Environment.getExternalStorageDirectory().getPath();
String apk_path = external_path + File.separator + "Android/data/com.youku.com/aiclk_down" + File.separator + "baidusearch_AndroidPhone_1037068k.apk";
File apkFile = new File(apk_path);
// 生成uri
Uri apkUri = getUri(context, apkFile);
// 通过uri安装
installApk(apkUri, context);
这里需要注意,external_path是storage/emulated/0这个目录,这个目录直接写入文件似乎是不可以的(创建文件夹可以),因此我们把apk存放在storage/emulated/0的子目录下,确保不发生权限问题。
生成uri:
private static Uri getUri(Context context, File file) {
if (file == null) {
return null;
}
Uri uri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = CPCFileProvider.getUriForFile(context, context.getPackageName() + ".CPCFileProvider", file);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
我们这里自定义了一个FileProvider,单纯继承自安卓提供的基类
android.support.v4.content.FileProvider
注意在获取uri的时候,第二个参数的内容需要与external-path里定义的内容相同。
<external-path name="external_files" path="."/>
下载apk:
private static void installApk(Uri apkUri, Context context) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
下载apk需要通过启动一个activity实现,因为高版本的andorid系统要求安装app需要显式得到用户同意。
这里需要注意intent.addFlags可以为一个intent添加多个flag属性。但是setFlags会只保留一个flag属性,建议以后只使用addFlags,避免某些属性被setFlags冲掉。
指定目录写一个txt文件并读出
给一个文件写入字符串的方法,与provider无关:
private static void writeText(File file, String content) {
if (TextUtils.isEmpty(content)) {
return;
}
OutputStreamWriter osw = null;
try {
osw = new OutputStreamWriter(new FileOutputStream(file, false), StandardCharsets.UTF_8);
osw.write(content);
osw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过uri读取一个文件里的字符串:
private static void readText(Uri fileUri, Context context) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(fileUri);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line);
content.append("\n"); // 如果需要逐行读取,则添加换行符
}
// 使用读取的内容进行处理
String fileContent = content.toString();
// 关闭 BufferedReader 和 InputStream
reader.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
可能需要创建文件夹:
private static void createFolder() {
String folderName = "aiclk_down";
File folder = new File(Environment.getExternalStorageDirectory(), "Android/data/com.youku.phone/" + folderName);
if (!folder.exists()) {
boolean success = folder.mkdirs();
if (success) {
// 文件夹创建成功
} else {
// 文件夹创建失败
}
}
}
知道各个子功能的实现后,就可以组装下代码了。思路就是创建文件->写入内容->读取内容。只是在读取的时候是用FileProvider生成的uri读取的。
public static void writeFileToExternalPath(Context context) {
if (context == null) {
return;
}
createFolder();
String external_path = Environment.getExternalStorageDirectory().getPath();
// 设定目标路径与文件名称
String targetPath = external_path + File.separator + "Android/data/com.youku.phone/aiclk_down" + File.separator +"test.txt";
File file = new File(targetPath);
try {
if (!file.exists()) {
// 创建文件
file.createNewFile();
}
// 给文件写入字符串
writeText(file, "测试");
} catch (Exception e) {
e.printStackTrace();
}
// 通过provider生成uri
Uri uri = getUri(context, file);
// 读取目标文件夹的字符串
readText(uri, context);
}
从两个程序中可以看出,uri是对绝对路径的再封装,提升了安全性。