把apk文件放到assets文件夹下 自动运行

本文介绍如何从Android应用的assets文件夹中安装APK。首先将APK文件复制到外部存储,然后通过Intent启动安装流程。文章还涉及AssetManager类的使用及权限设置。

从整体上看,一般的对于assets 里面的apk进行安装的操作是先将 apk 复制到sd上 或者其他的可读取存储位置。比如我拿到的机子 有两个路径

 /mnt/emmc/ 手机的内部存储位置(其他的手机不一定有)

 /mnt/sdcard/ 手机的sd存储位置

 复制到这两个路径都OK。


首先要获取assets目录下文件的数据流,用于写到存储位置上。

//这里的fileName 这个是assets文件下的全文件名 包括后缀名。

path 是存储的路径位置,绝对路径。

InputStream is = context.getAssets().open(fileName);
File file = new File(path);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
byte[] temp = new byte[1024];
int i = 0;
while ((i = is.read(temp)) > 0) {
fos.write(temp, 0, i);
}
fos.close();
is.close();

通过Context 获取到AssetManager

abstract  AssetManager getAssets()
Return an AssetManager instance for your application's package.
在Google sdk 上如此解释 返回一个 AssetManager

final  InputStream open( String fileName)
Open an asset using ACCESS_STREAMING mode.
final  InputStream open( String fileName, int accessMode)
Open an asset using an explicit access mode, returning an InputStream to read its contents.
AssetManager 有着两种方式获取到InputStream 第二种带入accessMode 是对 访问权限控制的

此时获取到了输入流 然后输出就OK,注意close 没其他的问题。 一会回头详细分析这个AssetManager。


这里所谓的安装就是打开apk 百度有很多答案,我给出一个我测试通过的代码


Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.apk"),
 "application/vnd.android.package-archive");
mContext.startActivity(intent);

我在下面提供整体的代码


[java]  view plain copy
  1. package com.example.testinstallapk;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7.   
  8. import android.net.Uri;  
  9. import android.os.Bundle;  
  10. import android.os.Environment;  
  11. import android.app.Activity;  
  12. import android.app.AlertDialog;  
  13. import android.app.AlertDialog.Builder;  
  14. import android.app.Dialog;  
  15. import android.content.Context;  
  16. import android.content.DialogInterface;  
  17. import android.content.DialogInterface.OnClickListener;  
  18. import android.content.Intent;  
  19. import android.view.Menu;  
  20. import android.widget.Toast;  
  21.   
  22. public class MainActivity extends Activity {  
  23.     Context mContext;  
  24.     @Override  
  25.     protected void onCreate(Bundle savedInstanceState) {  
  26.         super.onCreate(savedInstanceState);  
  27.         setContentView(R.layout.activity_main);  
  28.         mContext = this;  
  29.         //Toast.makeText(this, ""+Environment.getExternalStorageDirectory().getAbsolutePath(), 0).show();  
  30.         if(copyApkFromAssets(this"test.apk", Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.apk")){  
  31.             Builder m = new AlertDialog.Builder(mContext)  
  32.                                 .setIcon(R.drawable.ic_launcher).setMessage("是否安装?")  
  33.                                 .setIcon(R.drawable.ic_launcher)  
  34.                                 .setPositiveButton("yes"new OnClickListener() {  
  35.                                     @Override  
  36.                                     public void onClick(DialogInterface dialog, int which) {  
  37.                                         Intent intent = new Intent(Intent.ACTION_VIEW);  
  38.                                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  39.                                         intent.setDataAndType(Uri.parse("file://" + Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.apk"),  
  40.                                                        "application/vnd.android.package-archive");  
  41.                                         mContext.startActivity(intent);  
  42.                                         }  
  43.                                     });  
  44.             m.show();  
  45.         }  
  46.           
  47.     }  
  48.      public boolean copyApkFromAssets(Context context, String fileName, String path) {  
  49.          boolean copyIsFinish = false;  
  50.          try {  
  51.              InputStream is = context.getAssets().open(fileName);  
  52.              File file = new File(path);  
  53.              file.createNewFile();  
  54.              FileOutputStream fos = new FileOutputStream(file);  
  55.              byte[] temp = new byte[1024];  
  56.              int i = 0;  
  57.              while ((i = is.read(temp)) > 0) {  
  58.                  fos.write(temp, 0, i);  
  59.              }  
  60.              fos.close();  
  61.              is.close();  
  62.              copyIsFinish = true;  
  63.          } catch (IOException e) {  
  64.              e.printStackTrace();  
  65.          }  
  66.          return copyIsFinish;  
  67.      }  
  68. }  


注意在manifest中添加你的sd权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


现在分析一下这个 AssetManager 类。

为了分析这个类,先介绍一下assets这个文件夹

Android 系统为每个新设计的程序提供了/assets目录,这个目录保存的文件可以打包在程序里。/res 和/assets的不同点是,android不为/assets下的文件生成ID。如果使用/assets下的文件,需要指定文件的路径和文件名(是全名)

下面写一个方法遍历assets下面的全部文件

AssetManager  mAssetManager= getAssets();
String[] files = null;
try {
files = mAssetManager.list("");//为什么是空呢
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(String temp:files) Log.v("shenwenjian",""+temp);

final  String[] list( String path)
Return a String array of all the assets at the given path.
返回一个包含在assets中给定路径的所有文件 数组,

我为了获取所有故这里填"" 这时候得到几个字符串分别是images, sounds,webkit 当然你也可以放其他的文件 也会被打印出来.

 怎么读取文件,获取到文件内容呢?先获取上面说的获取数据流。

final  InputStream open( String fileName)
Open an asset using ACCESS_STREAMING mode.
final  InputStream open( String fileName, int accessMode)
通过这两个方法就可获取到输入流,然后通过  ByteArrayOutputStream 将inputstream 转换成string 即可以看到文件内容

关于那个打开APK的还需要分析。

主要就是解析那个intent 和策略等

这里给定一个apk安装,卸载和更新的连接。

http://blog.youkuaiyun.com/netpirate/article/details/5801379

http://www.devdiv.com/Android-%E5%A6%82%E4%BD%95%E6%89%93%E5%BC%80assets%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%E7%9A%84apk_-thread-38839-1-1.html

谢谢该链接的内容!

<think>我们正在讨论如何获取Unity中StreamingAssets文件夹下的文件。根据引用内容,我们可以总结出以下关键点: 1. 引用[1]展示了如何获取StreamingAssets目录下所有文件:使用`Application.dataPath`组合路径,然后通过`DirectoryInfo`和`FileInfo`遍历文件。 2. 引用[2]提到了使用`Application.streamingAssetsPath`来获取StreamingAssets文件夹的路径,并保存文件。 3. 引用[3]提醒在安卓平台上要避免使用中文路径,否则可能导致打包错误。 因此,我们可以得出以下步骤: ### 步骤1:获取StreamingAssets文件夹路径 Unity提供了`Application.streamingAssetsPath`属性,该属性返回StreamingAssets文件夹的完整路径。在不同平台下,这个路径有所不同: - 在Unity编辑器中,路径类似于`<项目路径>/Assets/StreamingAssets`。 - 在Android平台上,路径在jar包中(使用`file://`协议访问)。 - 在Windows、Mac等平台,路径在应用的数据文件夹内。 ### 步骤2:遍历文件夹并获取文件 由于不同平台下访问方式可能不同,我们需要注意: - 在编辑器和Windows/Mac等平台,我们可以直接使用System.IO的API(如`Directory`、`DirectoryInfo`)来访问。 - 在Android平台,StreamingAssets文件夹在压缩的jar包中,不能直接使用System.IO读取。此时需要采用UnityWebRequest或WWW(已过时)来读取文件内容,但无法直接获取文件列表。 因此,我们需要区分平台: #### 方法1:在编辑器和桌面平台(Windows、Mac、Linux)使用System.IO ```csharp using System.IO; using UnityEngine; public class GetStreamingAssetsFiles : MonoBehaviour { void Start() { // 获取StreamingAssets文件夹路径 string path = Application.streamingAssetsPath; // 检查目录是否存在 if (Directory.Exists(path)) { // 获取所有文件(包括子文件夹) string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); foreach (string file in files) { // 跳过.meta文件 if (file.EndsWith(".meta")) continue; Debug.Log("File Path: " + file); } } else { Debug.LogError("StreamingAssets directory not found!"); } } } ``` #### 方法2:在Android平台的处理 在Android平台,我们无法直接获取文件列表。一个常见的做法是维护一个文件列表的清单(比如一个文本文件),在打包生成这个清单,然后在运行时读取这个清单文件来获取文件列表。 **步骤:** 1. 在打包前,使用编辑器脚本生成一个包含所有StreamingAssets文件路径的清单文件(例如files.txt),并放到StreamingAssets文件夹中。 2. 运行时,在Android平台读取这个清单文件来获取文件列表。 **生成清单的编辑器脚本(放在Editor文件夹下):** ```csharp using UnityEditor; using System.IO; using System.Text; public class GenerateFileList { [MenuItem("Tools/Generate StreamingAssets File List")] public static void Generate() { string streamingAssetsPath = Application.streamingAssetsPath; StringBuilder sb = new StringBuilder(); // 遍历所有文件(不包括.meta文件) string[] files = Directory.GetFiles(streamingAssetsPath, "*", SearchOption.AllDirectories); foreach (string file in files) { if (file.EndsWith(".meta")) continue; // 获取相对路径 string relativePath = file.Replace(Application.dataPath, "").Replace("\\", "/").TrimStart('/'); sb.AppendLine(relativePath); } // 将清单写入StreamingAssets文件夹 string outputFile = Path.Combine(streamingAssetsPath, "files.txt"); File.WriteAllText(outputFile, sb.ToString()); AssetDatabase.Refresh(); } } ``` **运行时读取清单文件(跨平台):** ```csharp using System.Collections; using UnityEngine; public class GetStreamingAssetsFiles : MonoBehaviour { IEnumerator Start() { string fileListPath = Path.Combine(Application.streamingAssetsPath, "files.txt"); // 根据平台选择读取方式 if (Application.platform == RuntimePlatform.Android) { // 在Android上使用UnityWebRequest读取 UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.Get(fileListPath); yield return request.SendWebRequest(); if (request.result == UnityEngine.Networking.UnityWebRequest.Result.Success) { string fileListText = request.downloadHandler.text; string[] files = fileListText.Split(new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries); foreach (string file in files) { Debug.Log("File in StreamingAssets: " + file); } } else { Debug.LogError("Failed to read file list: " + request.error); } } else { // 其他平台直接读取 if (File.Exists(fileListPath)) { string fileListText = File.ReadAllText(fileListPath); string[] files = fileListText.Split(new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries); foreach (string file in files) { Debug.Log("File in StreamingAssets: " + file); } } } } } ``` ### 注意事项 1. **路径分隔符**:在Windows上路径使用反斜杠`\`,而Unity内部使用正斜杠`/`,建议在代码中统一使用正斜杠或使用`Path.Combine`。 2. **Android平台的特殊性**:在Android上,StreamingAssets文件夹内的文件在构建时会被压缩,因此不能直接通过System.IO读取。读取单个文件内容时也需要使用`UnityWebRequest`或`WWW`(已过时)。 3. **中文路径问题**:如引用[3]所述,在Android平台要避免使用中文路径和文件名,否则可能导致打包失败或读取问题[^3]。 4. **文件过滤**:注意跳过.meta文件,因为它们是Unity生成的元文件。 ### 总结 - 在编辑器和桌面平台,可以直接使用System.IO来获取StreamingAssets文件夹下的文件列表。 - 在Android平台,需要通过提前生成的清单文件来获取文件列表,并使用UnityWebRequest读取。 - 避免使用中文路径和文件名,以防止打包或读取问题。 §§相关问题§§ 1. 如何在Unity中读取StreamingAssets文件夹下的文本文件内容? 2. Unity在Android平台访问StreamingAssets文件夹有哪些限制? 3. 如何解决Unity中不同平台的文件路径差异问题? </think> # Unity中获取StreamingAssets文件夹文件的完整指南 在Unity中获取StreamingAssets文件夹下的文件需要根据平台差异使用不同方法,以下是详细解决方案: ## 🖥️ 1. 基本文件获取方法(适用于编辑器/PC平台) ```csharp using System.IO; using UnityEngine; public class StreamingAssetsLoader : MonoBehaviour { void Start() { // 获取StreamingAssets完整路径(跨平台) string streamingPath = Application.streamingAssetsPath; // 检查目录是否存在 if (Directory.Exists(streamingPath)) { // 获取所有文件(包含子目录) DirectoryInfo directory = new DirectoryInfo(streamingPath); FileInfo[] files = directory.GetFiles("*", SearchOption.AllDirectories); foreach (FileInfo file in files) { // 跳过Unity的.meta文件 if (file.Name.EndsWith(".meta")) continue; Debug.Log($"文件名: {file.Name}"); Debug.Log($"完整路径: {file.FullName}"); Debug.Log($"所在目录: {file.DirectoryName}"); } } else { Debug.LogError("StreamingAssets目录不存在!"); } } } ``` ## 📱 2. Android平台特殊处理 在Android平台上,StreamingAssets文件会被压缩到APK中,需要使用`UnityWebRequest`读取: ```csharp IEnumerator LoadAndroidFiles() { string filePath = Path.Combine(Application.streamingAssetsPath, "你的文件名.扩展名"); // 添加file://前缀(Android必需) if (!filePath.StartsWith("file://")) filePath = "file://" + filePath; using (UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.Get(filePath)) { yield return request.SendWebRequest(); if (request.result == UnityEngine.Networking.UnityWebRequest.Result.Success) { // 处理文件内容 byte[] data = request.downloadHandler.data; string text = request.downloadHandler.text; } else { Debug.LogError($"加载失败: {request.error}"); } } } ``` ## ⚠️ 3. 重要注意事项 1. **路径获取**: - 始终使用`Application.streamingAssetsPath`获取路径(不要手动拼接) - 不同平台路径格式: - Windows/Mac:`<项目路径>/Assets/StreamingAssets` - Android:`jar:file://<APK路径>!/assets` - iOS:`<应用包>/Raw` 2. **中文路径问题**: - 避免在路径中使用中文,否则Android打包会失败[^3] - 解决方案:只使用英文文件名和目录名 3. **文件类型处理**: - 文本文件:直接读取为字符串 - 二进制文件(如图片、音频): ```csharp // 图片加载示例 Texture2D texture = new Texture2D(2, 2); texture.LoadImage(File.ReadAllBytes(imagePath)); ``` 4. **平台兼容性代码**: ```csharp IEnumerator LoadFile(string relativePath) { string path = Path.Combine(Application.streamingAssetsPath, relativePath); // Android和WebGL需要特殊处理 #if UNITY_ANDROID || UNITY_WEBGL if (!path.StartsWith("file://")) path = "file://" + path; using (var request = UnityEngine.Networking.UnityWebRequest.Get(path)) { yield return request.SendWebRequest(); // 处理结果... } #else // PC/iOS等平台直接读取 if (File.Exists(path)) { string content = File.ReadAllText(path); // 处理内容... } #endif } ``` ## 🔍 4. 最佳实践建议 1. **预生成文件列表**: - 在编辑器下生成文件清单,运行时直接读取清单 - 避免在移动平台遍历目录(性能差) 2. **异步加载**: - 使用`UnityWebRequest`或`System.Threading.Tasks`异步操作 - 避免阻塞主线程 3. **文件缓存**: - 移动平台首次读取后缓存到`Application.persistentDataPath` - 后续访问使用缓存文件 ## 📚 总结 1. PC/编辑器平台使用`System.IO`直接访问文件 2. Android平台使用`UnityWebRequest`加载文件 3. 始终使用`Application.streamingAssetsPath`获取路径 4. 避免中文文件名和路径 5. 二进制文件需要特殊处理 > **提示**:在真机测试前务必在目标平台验证文件访问逻辑,不同平台行为差异较大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值