预置文件到sdcard目录

2023-11-25 02:20
文章标签 目录 sdcard 预置

本文主要是介绍预置文件到sdcard目录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

了解为什么不可以直接预置

因为sdcard是挂载之后出现的,没法在编译的时候直接添加内容

无法直接预置,那么用什么替代

找一个已知会在编译的时候,可以预置文件的位置,这里用的是system文件夹
路径:

\device\mediatek\common\mid\common\system

原理是什么?

开启一个复制的服务,让sdcard加载的时候,复制system目录下的文件到需要的位置

方法

1.将需要的文件放到system目录下,可以有多级目录,这里在定义位置的时候做出选择

在这里插入图片描述
我这里放置来3张图片到extra目录下

2.这里建立一个package,做类似预置应用的操作

在这里插入图片描述
这里取个名叫CopyMedia,可以随便取名,注意在加包的时候做对应的修改
看目录可以知道有3个大文件,最上面那个就是我们的项目的代码。类似写安卓项目,目录层级是一样的,jni就是java和c#的互相调用,mk文件是编译的关键,据说12变成了bp文件,这里是11.
mk文件可以理解为说明书,具体可以看

https://blog.csdn.net/hejnhong/article/details/120585740

直接上CopyMedia的代码

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.mid.copymedia"android:versionCode="1"android:versionName="1.0"android:sharedUserId="android.uid.system" ><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name" ><service android:name=".CopyService"android:directBootAware="true"><intent-filter ><action android:name="mid.intent.action.COPYMEDIA"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></service><receiver android:name=".CopyReceiver"android:directBootAware="true">  <intent-filter>  <action android:name="android.intent.action.BOOT_COMPLETED" />  </intent-filter>  </receiver></application></manifest>

可以看到这里面没有Activity,只有一个服务和一个广播接收者,说明什么,没有界面。

CopyReceiver.java

package com.mid.copymedia;import java.io.File;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.os.SystemProperties;public class CopyReceiver extends BroadcastReceiver {private String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";private static final String SRC_S = "/system/extra";private static final String SRC_D = "/data/extra";private static final String DST_STR = "persist.sys.sd.defaultpath";private static final String DST = "sdcard";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();boolean copyOk = SystemProperties.get("persist.sys.mid.cpok","fail").equals("ok");//CopyJni.isCopyDown();CopyUtil.debug("onReceive action " + action);if(action.equals(BOOT_COMPLETED)){if(!copyOk){Intent copyIntent = new Intent(context, CopyService.class);context.startService(copyIntent);}}}public void doCopyStuff(final Context mContext){CopyJni.startProcess(mContext, SystemProperties.get("ro.preinstall.canreset", "yes").equals("yes") ?SRC_S:SRC_D, DST);}}

这个类,做了啥,定义了一堆的常量,还拿到了一个系统值,先通过action来筛选服务,这里没有直接调用doCopyStuff方法,而是通过开启一个服务,让服务去调用这个方法,为什么?很显然,这种操作只有可能是耗时,不方便在这里调用,为什么服务可以?这个需要去看对服务的定义了,不展开描述

CopyService.java

package com.mid.copymedia;import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;public class CopyService extends Service {	private CopyReceiver mCopyReceiver = new CopyReceiver();public static void debug(String msg){android.util.Log.d("xxczy","mid=>"+msg);}@Overridepublic IBinder onBind(Intent arg0) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();debug("CopyService onCreate");mCopyReceiver.doCopyStuff(this);}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubsuper.onStart(intent, startId);}@Overridepublic void onDestroy() {debug("CopyService onDestroy");super.onDestroy();}}

回过头去看CopyJni.startProcess(),这里好像啥都没做,但不可能,不在src文件中具体实现,那么就是在jni了,直接打开,可以看到

JNIEXPORT void JNICALL Java_com_mid_copymedia_CopyJni_startProcess(JNIEnv *env, jclass cls, jobject ctx, jstring src, jstring dst)
{/**jclass FindClass(JNIEnv *env, const char *name);*/jclass  CopyUtilClz = env->FindClass("com/mid/copymedia/CopyUtil");if(CopyUtilClz == NULL){LOGD("CopyJni_startProcess can't find CopyUtilClz \n");return;}/*	jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);*/jmethodID doCopyMthdId = env->GetStaticMethodID(CopyUtilClz, "doCopy","(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V");/**jstring NewStringUTF(JNIEnv *env, const char *bytes);*/// jstring src = env->NewStringUTF("/system/vendor_prebuilt");// jstring dst = env->NewStringUTF("/storage/sdcard0/vendor_media");/*NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz,jmethodID methodID, ...);*/env->CallStaticVoidMethod(cls,doCopyMthdId,ctx,src,dst);
}

这一看,就有点懵,反手查资料,可以知道
FindClass 该函数用于加载本地定义的类。它将搜索由CLASSPATH 环境变量为具有指定名称的类所指定的目录和 zip文件
CallStaticVoidMethod 调用静态方法
资料链接:

https://blog.csdn.net/prike/article/details/72790351?utm_source=blogkpcl7

嗯,可以看到又回去了,直接的意思就是把CopyUtil.java的静态方法全部调用了

CopyUtil.java

package com.mid.copymedia;import java.io.File;
import java.io.IOException;import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.os.SystemProperties;public class CopyUtil {public static void debug(String msg){android.util.Log.d("xxczy","mid=>"+msg);}public static String getRealPath(File file){try {debug("getRealPath getCanonicalPath="+file.getCanonicalPath()+" absPath="+file.getAbsolutePath());if(!file.getCanonicalPath().equals(file.getAbsolutePath())){return getRealPath(new File(file.getCanonicalPath()));}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return file.getAbsolutePath();}public static void doCopy(final Context ctx , final String SRC, final String DST){boolean copyOk = SystemProperties.get("persist.sys.mid.cpok","fail").equals("ok");//CopyJni.isCopyDown();debug("doCopyStuff copy "+ copyOk);if(!copyOk){new Thread(){public void run() {File src = new File(SRC);File dst =  new File(DST);String dstPath = dst.getAbsolutePath();String dstCanoinacal = dstPath;debug("dstPath="+dstPath);dstCanoinacal = getRealPath(dst);debug("dstCanoinacal="+dstCanoinacal);dst = new File(dstCanoinacal);boolean ret = true;if(!dst.exists()){ret = dst.mkdirs();}if(!ret){debug("mkdir error return now "+dstCanoinacal);return;}CopyJni.doSomething(src, dst);CopyJni.copyDown(ctx, dstPath);};}.start();}}public static void updateMedia(Context context, String filename){  MediaScannerConnection.scanFile(context,  new String[] { filename }, null,  new MediaScannerConnection.OnScanCompletedListener() {  public void onScanCompleted(String path, Uri uri) {  debug("Scanned " + path + ":");  debug("-> uri=" + uri);  }  });  } }

很显然这里做了3件事:
1.拿具体路径
2.复制文件
3.跟新数据

直接看复制文件

嗯,前面一看就知道,就是对路径的是否存在的判断,没有就创建对应的文件夹,后面又调用了**CopyJni.doSomething(src, dst);CopyJni.copyDown(ctx, dstPath);**方法

/** Class:     com_mid_copymedia_CopyJni* Method:    doSomething* Signature: (Ljava/io/File;Ljava/io/File;)V*/
JNIEXPORT void JNICALL Java_com_mid_copymedia_CopyJni_doSomething(JNIEnv *env, jclass cls, jobject srcFile, jobject dstFile)
{jclass FileUtilClz = env->FindClass("com/mid/copymedia/FileUtil");if(FileUtilClz == NULL){LOGD("CopyJni_doSomethind can't find FileUtilClz \n");return;}jmethodID copyFolderId = env->GetStaticMethodID(FileUtilClz, "copyFolder","(Ljava/io/File;Ljava/io/File;)V");env->CallStaticVoidMethod(cls,copyFolderId,srcFile,dstFile);}

/** Class:     com_mid_copymedia_CopyJni* Method:    copyDown* Signature: (Landroid/content/Context;Ljava/lang/String;)V*/
JNIEXPORT void JNICALL Java_com_mid_copymedia_CopyJni_copyDown(JNIEnv *, jclass, jobject, jstring);

嗯,感觉是吃太饱了,直接看FileUtil.java的代码

FileUtil.java

package com.mid.copymedia;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import android.util.Log;public class FileUtil {private static void debug(String msg) {android.util.Log.d("xxczy", "mid=>" + msg);}public static void copyFolder(File src, File dst) {debug("copyFolder " + src.getAbsolutePath() + " to "+ dst.getAbsolutePath());long startTime = System.currentTimeMillis();debug("src.isDir " + src.isDirectory() + " dst.isDir "+ dst.isDirectory());if (src.isDirectory() && dst.isDirectory()) {File[] srcFiles = src.listFiles();debug("srcFiles.len " + srcFiles.length);if (srcFiles != null) {File toFile = null;for (int i = 0; i < srcFiles.length; i++) {toFile = new File(dst, new String(srcFiles[i].getName().getBytes()));if (srcFiles[i].isDirectory()) {if (!toFile.exists()) {if (!toFile.mkdirs()) {debug("mkdirs failed "+ toFile.getAbsolutePath());continue;}}copyFolder(srcFiles[i], toFile);} else {copyfile(srcFiles[i], toFile, true);}}}}long endTime = System.currentTimeMillis();long totalMs = (endTime - startTime) / 1000;debug("totalTime = " + totalMs / 1000 + "s " + totalMs % 1000 + " ms");}public static void copyfile(File fromFile, File toFile, Boolean rewrite) {debug("start copy " + new String(fromFile.getAbsolutePath().getBytes())+ " to " + toFile.getAbsolutePath());long startTime = System.currentTimeMillis();if (!fromFile.exists()) {return;}if (!fromFile.isFile()) {return;}if (!fromFile.canRead()) {return;}if (!toFile.getParentFile().exists()) {toFile.getParentFile().mkdirs();}if (toFile.exists() && rewrite) {toFile.delete();}debug("check permission ok !");try {FileInputStream fosfrom = new FileInputStream(fromFile);FileOutputStream fosto = new FileOutputStream(toFile);byte[] bt = new byte[1024 * 128];int c;while ((c = fosfrom.read(bt)) > 0) {fosto.write(bt, 0, c);}fosfrom.close();fosto.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}long endTime = System.currentTimeMillis();long totalMs = (endTime - startTime) / 1000;debug("end copy file time = " + totalMs / 1000 + "s " + totalMs % 1000+ " ms");}public static void delete(File file) {if (file.isFile()) {file.delete();return;}if (file.isDirectory()) {File[] childFiles = file.listFiles();if (childFiles == null || childFiles.length == 0) {file.delete();return;}for (int i = 0; i < childFiles.length; i++) {delete(childFiles[i]);}file.delete();}}}

这里才是关键,用流去读取和写入文件
看过全部代码就知道了,有很多是多余的,就是个人对安卓系统开发的了解还较为浅,没有做实际修改
具体文件:

https://www.aliyundrive.com/s/aX6QJNadRbf

最后别忘了在\device\mediatek\system\common\device.mk中添加这个包名

PRODUCT_PACKAGES += CopyMedia

这篇关于预置文件到sdcard目录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/422970

相关文章

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

python获取当前文件和目录路径的方法详解

《python获取当前文件和目录路径的方法详解》:本文主要介绍Python中获取当前文件路径和目录的方法,包括使用__file__关键字、os.path.abspath、os.path.realp... 目录1、获取当前文件路径2、获取当前文件所在目录3、os.path.abspath和os.path.re

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

CentOS下mysql数据库data目录迁移

https://my.oschina.net/u/873762/blog/180388        公司新上线一个资讯网站,独立主机,raid5,lamp架构。由于资讯网是面向小行业,初步估计一两年内访问量压力不大,故,在做服务器系统搭建的时候,只是简单分出一个独立的data区作为数据库和网站程序的专区,其他按照linux的默认分区。apache,mysql,php均使用yum安装(也尝试

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录 在深度学习项目中,目标检测是一项重要的任务。本文将详细介绍如何使用Detectron2进行目标检测模型的复现训练,涵盖训练数据准备、训练命令、训练日志分析、训练指标以及训练输出目录的各个文件及其作用。特别地,我们将演示在训练过程中出现中断后,如何使用 resume 功能继续训练,并将我们复现的模型与Model Zoo中的

Java Web应用程序的推荐目录结构

以前没有用过maven管理过项目的依赖,最后使用上了maven,发现通过不能方式建立出来的web应用程序目录结构基本都不一样,既然每次都要到网上搜索如何建立maven管理的Web应用程序,不如自己找百度谷歌一下。 找了半天 ,感觉比较好的maven管理的web应用程序目录结构是这个: ├── pom.xml└── src├── main│ ├── java│ │ └── myg

src/pyaudio/device_api.c:9:10: fatal error: portaudio.h: 没有那个文件或目录

(venv) shgbitai@shgbitai-C9X299-PGF:~/pythonworkspace/ai-accompany$ pip install pyaudio sounddeviceCollecting pyaudioDownloading PyAudio-0.2.14.tar.gz (47 kB)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

为libpng不同架构创建构建目录、编译、安装以及合并库文件的所有步骤。

好的。既然你已经有了 libpng 的源代码,并且当前处在它的目录下,我们可以简化脚本,不再需要下载和解压源代码这一步。以下是修改后的脚本:```sh#!/bin/bash# 当前目录即 libpng 源代码目录LIBPNG_SRC_DIR=$(pwd)# 设置工作目录WORK_DIR=$(pwd)/libpng_buildBUILD_DIR_X86_64="$WORK_DIR/build

Spring Boot + Vue 多级目录的构建详解

1. 背景介绍 1.1 为何选择 Spring Boot + Vue? 在现代 Web 开发中,前后端分离已成为一种标准实践。Spring Boot 提供了强大的后端开发能力,尤其在构建企业级应用时,其轻量级、高效性和丰富的生态系统让开发者如虎添翼。而 Vue.js 则以其简单易学的语法和灵活的组件系统,成为前端开发的热门选择。结合这两个技术栈,我们可以轻松实现复杂的业务逻辑与优秀的用户体验。

Java传输本地目录到远程服务器

在使用Java进行开发时,有时需要将本地目录中的文件复制或传输到远程服务器上。这种场景在部署应用程序或进行数据迁移时尤为常见。JSch库提供了一种简便的方法来实现这一功能。以下是从Codekru网站获取的信息摘要,并结合相关内容,展示如何使用JSch库实现从本地计算机复制整个目录到远程服务器的过程。 准备工作 首先,确保您的项目中已经包含了JSch库的依赖。如果您使用Maven作为构建工具,可