预置文件到sdcard目录

编程入门 行业动态 更新时间:2024-10-21 15:27:09

预置<a href=https://www.elefans.com/category/jswz/34/1771438.html style=文件到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文件可以理解为说明书,具体可以看

直接上CopyMedia的代码

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns: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.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.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 调用静态方法
资料链接:

=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.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();}}}

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

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

PRODUCT_PACKAGES += CopyMedia

更多推荐

预置文件到sdcard目录

本文发布于:2024-02-06 02:57:03,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1745801.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:文件   目录   sdcard

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!