Unity3d android 通信之 unity3d读取android SD卡文件
2017-05-05 12:51
357 查看
此篇博文解决的问题是:
1、unity3d如何访问android SD卡的文件
2、如果把android端代码以jar包形式由unity3d调用
闲话不多说,现在咱们进入正题。
一、unity3d如何访问android SD卡的文件
实现效果是unity3d调用android相册或相机,选择一张图片剪裁后,将图片肯绘制到unity3d中。
解决这个问题,首先需要明白的是unity3d的资源存放目录,因为unity3d支持跨平台特性,所以资源文件的存放必然遵循一定的规则,否则很可能在不同的平台上编译会出现问题。
android平台对应的资源路径
具体的Unity3d的资源及目录说明可参考:http://www.tuicool.com/articles/qMNnmm6 ,此处不再缀述。
因此如果我们想要访问andorid
SD卡上的文件,必须使用持久化数据存储目录 Application.persistentDataPath,它在android上对应的目录为Android/data/xxx.xx.xx/files/ 文件夹。也就是说,unity3d读取android SD中的文件目录是固定的,这是一个私有目录。下面我们来实现这一功能。效果是,从相册中选择一张照片,剪裁后,讲照片保存到android app安装目录下的files文件夹中,然后由unity3d读取此图片,绘制到屏幕上。
1、我们创建一个Android工程,取名为UnitySDK,此工程的目的是把我们的android端代码打包成一个jar包,放入Unity3d中使用,这里使用的是Eclipse,记住包名需跟unity3D
android配置里的包名保持一致。
2、把我们的项目设置为一个Library
3、从unity的安装目录中找出classes.jar包,不同电脑文件存放位置可能不同,Windows平台如果使用mono方式的话,此文件在\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
中。将jar包引用到我们的项目中。
4、将MainActivity继承自UnityPlayerActivity
并移除setContentView()方法,这是因为UnityPlayerActivity 继承自Activity,它里面已经设置了unityPlayer作为界面渲染,如果不移除setContentView()方法,则会造成复写,看不到unity3d的界面。MainActivity里的代码如下:
在此我们定义了一个TakePhoto方法,,同时将处理结果交给WebViewActivity处理。WebViewActivity的代码如下,它的作用是用于打开相册/相机,选择照片后,进行剪裁,最后将剪裁结果保存到Android/data/com.demo.unity/files/ 目录下供unity3d调用。
public class WebViewActivity extends Activity {
ImageView imageView = null;
public static final int NONE = 0;
public static final int PHOTOHRAPH = 1;// 拍照
public static final int PHOTOZOOM = 2; // 缩放
public static final int PHOTORESOULT = 3;// 结果
public static final String IMAGE_UNSPECIFIED = "image/*";
public final static String FILE_NAME = "image.png";
public final static String DATA_URL = "/data/data/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
imageView = (ImageView) this.findViewById(R.id.imageID);
String type = this.getIntent().getStringExtra("type");
// 在这里判断是打开本地相册还是直接照相
if (type.equals("takePhoto")) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "temp.jpg")));
startActivityForResult(intent, PHOTOHRAPH);
} else {
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
startActivityForResult(intent, PHOTOZOOM);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == NONE)
return;
// 拍照
if (requestCode == PHOTOHRAPH) {
// 设置文件保存路径这里放在跟目录下
File picture = new File(Environment.getExternalStorageDirectory() + "/temp.jpg");
startPhotoZoom(Uri.fromFile(picture));
}
if (data == null)
return;
// 读取相册缩放图片
if (requestCode == PHOTOZOOM) {
startPhotoZoom(data.getData());
}
// 处理结果
if (requestCode == PHOTORESOULT) {
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap photo = extras.getParcelable("data");
imageView.setImageBitmap(photo);
try {
SaveBitmap(photo);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
public void startPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, IMAGE_UNSPECIFIED);
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", true);
startActivityForResult(intent, PHOTORESOULT);
}
public void SaveBitmap(Bitmap bitmap) throws IOException {
FileOutputStream fOut = null;
// 注解1
// String path = "/mnt/sdcard/Android/data/com.xys/files";
String path = "/storage/emulated/0/Android/data/com.demo.unity/files";
try {
// 查看这个路径是否存在,
// 如果并没有这个路径,
// 创建这个路径
File destDir = new File(path);
if (!destDir.exists()) {
destDir.mkdirs();
}
fOut = new FileOutputStream(path + "/" + FILE_NAME);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 将Bitmap对象写入本地路径中,Unity在去相同的路径来读取这个文件
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
try {
fOut.flush();
} catch (IOException e) {
e.printStackTrace();
}
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
// 通知Unity开始在"/mnt/sdcard/Android/data/com.xys/files";路径中读取图片资源,并且现在在Unity中
UnityPlayer.UnitySendMessage("Main Camera", "message", FILE_NAME);
finish();
}}
注意 com.demo.unity是我项目的包名,实际使用过程中请注意替换。
WebViewActivity布局文件如下:
Manifest中代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demo.unity"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<!-- 连接互联网的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name="com.demo.unity.MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.demo.unity.TestActivity0"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
<activity
android:name="com.demo.unity.WebViewActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
</application>
</manifest>
注意: 把android:theme换成android自带的主题
5、至此,android端代码基本编写完成,clean一下项目,在bin目录下找到
对应jar包,此jar包即为unity3d需要用到的jar包。
6、创建unity项目,并在Assets目录下依次创建
Plugins 和Android文件夹,将android
资源文件放到res目录下,Eclipse里的jar包,放到bin目录下,Manifest文件,放到 Android文件夹下:
注意:values中的style文件、dimen文件不要复制过去
7、编写Main
Camera 的 C#文件,MainControl,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainControl : MonoBehaviour {
public GUISkin skin;
Texture texture;
string path="";
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//当用户按下手机的返回键或home键退出游戏
if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Home) )
{
Application.Quit();
}
}
void OnGUI()
{
GUILayout.Button (path, GUILayout.Height (100));
GUI.skin = skin;
if(GUILayout.Button("打开手机相册",GUILayout.Height(100)))
{
//调用我们制作的Android插件打开手机相册
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("TakePhoto","takeSave");
}
if(GUILayout.Button("打开手机摄像机",GUILayout.Height(100)))
{
//调用我们制作的Android插件打开手机摄像机
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("TakePhoto","takePhoto");
}
if(texture != null)
{
//注意! 我们在这里绘制Texture对象,该对象是通过
//我们制作的Android插件得到的,当这个对象不等于空的时候
//直接绘制。
GUI.DrawTexture(new Rect(300,300,600,600),texture);
}
}
void message(string str){
StartCoroutine(LoadTexture(str));
}
IEnumerator LoadTexture(string name)
{
//注解1
path = "file://" + Application.persistentDataPath +"/" + name;
WWW www = new WWW(path);
while (!www.isDone)
{
}
yield return www;
//为贴图赋值
texture = www.texture;
}
}
最后来张效果图~:
源码地址:https://pan.baidu.com/s/1bo7ezDl
其中,UnityDemo为unity创建的项目,UnitySDK为android项目。
1、unity3d如何访问android SD卡的文件
2、如果把android端代码以jar包形式由unity3d调用
闲话不多说,现在咱们进入正题。
一、unity3d如何访问android SD卡的文件
实现效果是unity3d调用android相册或相机,选择一张图片剪裁后,将图片肯绘制到unity3d中。
解决这个问题,首先需要明白的是unity3d的资源存放目录,因为unity3d支持跨平台特性,所以资源文件的存放必然遵循一定的规则,否则很可能在不同的平台上编译会出现问题。
Unity3D中的资源路径
Application.dataPath | 此属性用于返回程序的数据文件所在文件夹的路径。例如在Editor中就是Assets了。 |
Application.streamingAssetsPath | 此属性用于返回流数据的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径。 |
Application.persistentDataPath | 此属性用于返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。 |
Application.temporaryCachePath | 此属性用于返回一个临时数据的缓存目录。 |
Application.dataPath | /data/app/xxx.xxx.xxx.apk |
Application.streamingAssetsPath | jar:file:///data/app/xxx.xxx.xxx.apk/!/assets |
Application.persistentDataPath | /data/data/xxx.xxx.xxx/files |
Application.temporaryCachePath | /data/data/xxx.xxx.xxx/cache |
因此如果我们想要访问andorid
SD卡上的文件,必须使用持久化数据存储目录 Application.persistentDataPath,它在android上对应的目录为Android/data/xxx.xx.xx/files/ 文件夹。也就是说,unity3d读取android SD中的文件目录是固定的,这是一个私有目录。下面我们来实现这一功能。效果是,从相册中选择一张照片,剪裁后,讲照片保存到android app安装目录下的files文件夹中,然后由unity3d读取此图片,绘制到屏幕上。
1、我们创建一个Android工程,取名为UnitySDK,此工程的目的是把我们的android端代码打包成一个jar包,放入Unity3d中使用,这里使用的是Eclipse,记住包名需跟unity3D
android配置里的包名保持一致。
2、把我们的项目设置为一个Library
3、从unity的安装目录中找出classes.jar包,不同电脑文件存放位置可能不同,Windows平台如果使用mono方式的话,此文件在\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
中。将jar包引用到我们的项目中。
4、将MainActivity继承自UnityPlayerActivity
并移除setContentView()方法,这是因为UnityPlayerActivity 继承自Activity,它里面已经设置了unityPlayer作为界面渲染,如果不移除setContentView()方法,则会造成复写,看不到unity3d的界面。MainActivity里的代码如下:
public class MainActivity extends UnityPlayerActivity { Context mContext = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; } // Unity中会调用这个方法,用于区分打开摄像机 开始本地相册 public void TakePhoto(String str) { Intent intent = new Intent(mContext, WebViewActivity.class); intent.putExtra("type", str); this.startActivity(intent); }
}
在此我们定义了一个TakePhoto方法,,同时将处理结果交给WebViewActivity处理。WebViewActivity的代码如下,它的作用是用于打开相册/相机,选择照片后,进行剪裁,最后将剪裁结果保存到Android/data/com.demo.unity/files/ 目录下供unity3d调用。
public class WebViewActivity extends Activity {
ImageView imageView = null;
public static final int NONE = 0;
public static final int PHOTOHRAPH = 1;// 拍照
public static final int PHOTOZOOM = 2; // 缩放
public static final int PHOTORESOULT = 3;// 结果
public static final String IMAGE_UNSPECIFIED = "image/*";
public final static String FILE_NAME = "image.png";
public final static String DATA_URL = "/data/data/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
imageView = (ImageView) this.findViewById(R.id.imageID);
String type = this.getIntent().getStringExtra("type");
// 在这里判断是打开本地相册还是直接照相
if (type.equals("takePhoto")) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "temp.jpg")));
startActivityForResult(intent, PHOTOHRAPH);
} else {
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
startActivityForResult(intent, PHOTOZOOM);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == NONE)
return;
// 拍照
if (requestCode == PHOTOHRAPH) {
// 设置文件保存路径这里放在跟目录下
File picture = new File(Environment.getExternalStorageDirectory() + "/temp.jpg");
startPhotoZoom(Uri.fromFile(picture));
}
if (data == null)
return;
// 读取相册缩放图片
if (requestCode == PHOTOZOOM) {
startPhotoZoom(data.getData());
}
// 处理结果
if (requestCode == PHOTORESOULT) {
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap photo = extras.getParcelable("data");
imageView.setImageBitmap(photo);
try {
SaveBitmap(photo);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
public void startPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, IMAGE_UNSPECIFIED);
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", true);
startActivityForResult(intent, PHOTORESOULT);
}
public void SaveBitmap(Bitmap bitmap) throws IOException {
FileOutputStream fOut = null;
// 注解1
// String path = "/mnt/sdcard/Android/data/com.xys/files";
String path = "/storage/emulated/0/Android/data/com.demo.unity/files";
try {
// 查看这个路径是否存在,
// 如果并没有这个路径,
// 创建这个路径
File destDir = new File(path);
if (!destDir.exists()) {
destDir.mkdirs();
}
fOut = new FileOutputStream(path + "/" + FILE_NAME);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 将Bitmap对象写入本地路径中,Unity在去相同的路径来读取这个文件
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
try {
fOut.flush();
} catch (IOException e) {
e.printStackTrace();
}
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
// 通知Unity开始在"/mnt/sdcard/Android/data/com.xys/files";路径中读取图片资源,并且现在在Unity中
UnityPlayer.UnitySendMessage("Main Camera", "message", FILE_NAME);
finish();
}}
注意 com.demo.unity是我项目的包名,实际使用过程中请注意替换。
WebViewActivity布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <ImageView android:layout_gravity="center" android:id="@+id/imageID" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
Manifest中代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demo.unity"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<!-- 连接互联网的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name="com.demo.unity.MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.demo.unity.TestActivity0"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
<activity
android:name="com.demo.unity.WebViewActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
</application>
</manifest>
注意: 把android:theme换成android自带的主题
5、至此,android端代码基本编写完成,clean一下项目,在bin目录下找到
对应jar包,此jar包即为unity3d需要用到的jar包。
6、创建unity项目,并在Assets目录下依次创建
Plugins 和Android文件夹,将android
资源文件放到res目录下,Eclipse里的jar包,放到bin目录下,Manifest文件,放到 Android文件夹下:
注意:values中的style文件、dimen文件不要复制过去
7、编写Main
Camera 的 C#文件,MainControl,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainControl : MonoBehaviour {
public GUISkin skin;
Texture texture;
string path="";
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//当用户按下手机的返回键或home键退出游戏
if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Home) )
{
Application.Quit();
}
}
void OnGUI()
{
GUILayout.Button (path, GUILayout.Height (100));
GUI.skin = skin;
if(GUILayout.Button("打开手机相册",GUILayout.Height(100)))
{
//调用我们制作的Android插件打开手机相册
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("TakePhoto","takeSave");
}
if(GUILayout.Button("打开手机摄像机",GUILayout.Height(100)))
{
//调用我们制作的Android插件打开手机摄像机
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("TakePhoto","takePhoto");
}
if(texture != null)
{
//注意! 我们在这里绘制Texture对象,该对象是通过
//我们制作的Android插件得到的,当这个对象不等于空的时候
//直接绘制。
GUI.DrawTexture(new Rect(300,300,600,600),texture);
}
}
void message(string str){
StartCoroutine(LoadTexture(str));
}
IEnumerator LoadTexture(string name)
{
//注解1
path = "file://" + Application.persistentDataPath +"/" + name;
WWW www = new WWW(path);
while (!www.isDone)
{
}
yield return www;
//为贴图赋值
texture = www.texture;
}
}
最后来张效果图~:
源码地址:https://pan.baidu.com/s/1bo7ezDl
其中,UnityDemo为unity创建的项目,UnitySDK为android项目。
相关文章推荐
- android读取内存和sd卡中的txt文件
- Unity3D IOS Android支持中文与本地文件的读取写入
- Android之根据读取SD卡指定后缀名的文件
- Android开发笔记——从SD卡保存和读取文件
- Android 之 使用File类在SD卡中读取数据文件
- android, 删除SD卡音乐文件。通过getContentResolver读取音乐文件,可以获取到一个完整的路径,直接new File(这括号写获取的路径).delete();
- android 随手记--读取sd卡txt文件
- android读取sd卡数据库文件相关问题
- android,保存文件到sd卡和读取
- 转-Android 之 使用File类在SD卡中读取数据文件
- android 读取SD卡文件
- android 读取SD卡下TXT文件
- [转载]android读取sd卡文件的工具类
- Unity3D 游戏引擎之IOS Android支持中文与本地文件的读取写入
- android 读取SD卡下TXT文件
- android(安卓)sd卡写入 读取文件的例子
- android 读取SD卡或者其他地方文件功能函数
- Android--SD卡上的创建、读取、写入文件及目录
- Android 之 使用File类在SD卡中读取数据文件
- Android从SD卡中读取所有的文件