admin 管理员组

文章数量: 887016

Unity调用android相册获取图片或视频

(此文章对有unity基础和对环境配置有基础的童嚡容易看懂)
因为项目上用到,在百度了很多大佬的文章后,陆陆续续踩了很多坑,可能是我哪里设置的不对,大部分都没成功,后面捣鼓捣鼓着就出来了,如有哪里不对,还请各位大佬多多指教,下面进入正题
创建一个unity项目,设置unity的包名(例:com.公司名.项目包名)

在assets路径下创建一个Plugins文件夹,这个文件夹一般用来放置需要调用的dll文件,然后在Plugins路径下创建一个Android文件夹(为后面放置aar文件使用),代码后面一起添加。
我是用的AndroidStudio3.5.2版本,安装Android Studio及环境配置教程比较多,就直接带过,打开Android studio,新建项目


然后点击Next下一步

然后点击finish完成,项目构建中,需要几秒钟完成后的出现这个窗口

不用理会,直接Close掉就可以了,创建完成,显示是这样的

然后点击Android图标切换样式,选择Project模式

选完后如下图

打开src文件夹下的main,里面有项目自带的类MyActivity,可以删掉自己建,但我个人比较懒,缩直接修改自带的,打开myactivity然后删掉里面的方法,复制下面的代码到myactivity类中(直接在网上复制了其他博主的,手动狗头)

package com.Companys.Test;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.unity3d.player.UnityPlayerActivity;

public class MainActivity extends UnityPlayerActivity{
    private static String LOG_TAG = "LOG_My";
    Context mContext = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
    }

    //Unity中会调用这个方法,用于打开本地相册
    public void TakePhoto(String str)
    {
        Log.d(LOG_TAG,str);
        Intent intent = new Intent(mContext,WebViewActivity.class);
        this.startActivity(intent);
    }
}

TakePhoto这个方法要在unity里面调用的,可以改为自己喜欢的名称,不过在android中改了,在unity也要修改,否则无法调用,复制完后如下

注意第一行的Package包名不用复制,每个人的对应自己建的包名就可以了,复制完后你会发现报错了,这是因为类里面引用unity的类,但这个引用为空,这时就要导入一个jar引用,类似于unity里的dll一样,这个jar文件在unity的安装目录下,要注意你当前创建的unity项目所使用的版本,不是那个版本都可以,我用的是2018.3.8版本,路径为Unity2018.3.8\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes下有个Class.jar,将这个jar文件复制一份,放到刚刚android的项目文件libs文件夹下,如下图

放置完后,文件就在libs文件夹中,但你会发现代码还是报错的,因为还需要再设置下,选中class.jar,然后右键选择Add as Library,如下图

添加后,你会发现很多的报错都没了,但还有一个地方报错,那是因为有个被调用的类不存在,我们直接创建就好了,选中MyActivity所在的文件夹,然后右键New—Java Class,创建一个java类,类名为WebViewActivity,创建完后报错信息就没了,修改WebViewActivity类,将下面的代码复制到WebViewActivity类中,选择图片或视频都在这里,仔细看呦

package com.Companys.Test;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import com.unity3d.player.UnityPlayer;
import java.io.IOException;
//import android.view.KeyEvent;

public class WebViewActivity extends Activity
{
    public static final int NONE = 0;
    public static final int PHOTORESOULT = 3;
    public static final String IMAGE_UNSPECIFIED = "video/*"/*;"image/*"*/;//划重点,这里指定视频或图片

    private String LOG_TAG = "LOG_ZDQ";
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        Intent intent = new Intent(Intent.ACTION_PICK, null);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
        startActivityForResult(intent, PHOTORESOULT);
        Log.d(LOG_TAG, "打开相册!");
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(LOG_TAG, "resultCode :" + resultCode);
        if (resultCode == NONE)
        {
            if (data == null)
            {
                this.finish();
                UnityPlayer.UnitySendMessage("InputURL","GetPhoto","");
            }else
            {
                if(this.isFinishing() == false)
                {
                    this.finish();
                }
                UnityPlayer.UnitySendMessage("InputURL","GetPhoto","");
            }
            return;
        }

        if (data == null)
        {
            this.finish();
            UnityPlayer.UnitySendMessage("InputURL","GetPhoto","");
        }

        ContentResolver resolver = getContentResolver();
        Bitmap bm=null;

        Uri originalUri = data.getData();
        try {
            bm = MediaStore.Images.Media.getBitmap(resolver, originalUri);
        } catch (IOException e) {
            e.printStackTrace();
        }


        String[] proj = {MediaStore.Images.Media.DATA};

        Cursor cursor= getContentResolver().query(originalUri,proj,null,null,null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String _path = cursor.getString(column_index);

        UnityPlayer.UnitySendMessage("InputURL", "GetPhoto", _path);
        super.onActivityResult(requestCode, resultCode, data);
        this.finish();
    }
}

有个地方注意下,代码块中有个 “InputURL”,找不到可以复制这个然后按F12查找,这个名称是你在unity里面挂载脚本的物体名称,后面unity模块会提下
然后不需要再修改当前app目录文件夹下其他文件,直接右键当前的总项目名称,选择New-----Module,新建一个Module

选择Android Library样式,点击Next下一步

然后点击finish完成,等几秒钟就可以编译完成,然后将app里的刚才修改和新建的脚本拷贝到新建的android library中的同样路径下

然后也同样将class.jar文件也拷贝到libs文件夹中,然后右键选择add as library,默认点确定就可以了,不用改啥,完成后是这样

然后找到新建library中的AndroidManifest.xml,打开进行修改

<manifest xmlns:android="http://schemas.android/apk/res/android"
    package="com.Companys.Test" >
    <!--读取相册权限 (必须)-->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <application   >
         <activity android:name=".MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
         <activity
             android:name=".WebViewActivity">
         </activity>
     </application>
 </manifest>

将上面的代码复制到xml中,注意不要复制包名,这是我的包名,如果你的包名和我不一样,不要复制包名…
然后找到build.gradle,如图

双击打开它进行修改(其实这我也不知道要不要修改,因为这是打jar包中的设置,而我这是打aar包…狗头)

task makejar(type: Copy){
    //delete 'libs/test.jar'
    from('build/intermediates/packaged-classes/release/')//这个路径应该已经改了,反正我的是没有
    into('libs')
    include('classes.jar')
    rename('classes.jar','FarmGetAndroidPhoto.jar')
}

makejar.dependsOn(build)


改完后找到总项目结构目录下的gradle.properties文件,然后双击进行修改,如图

找到org.gradle.jvmargs这句,后面的xms可能不一样,但改它就对了,将这行代码注释掉,直接这行开头添加#号就可以了,然后保存下,接着打开androidstudio的安装目录,看看你Android Studio\bin下的studio.exe.vmoptions还是studio64.exe.vmoptions,然后打开进行修改,长这个样子的,直接对应着改就可以了

-Xms2048m
-Xmx2048m
-XX:ReservedCodeCacheSize=2048m


编辑完以后就基本上完成了,然后选择菜单栏里的Build选项下的Rebuild project,如图

点击Rebuild project后等待一会,等构建完后打开项目目录节点下的build文件夹,子文件夹outputs,里面有个aar文件夹,下面就是已经打包好的aar文件,如图

然后将这个aar文件和图中圈住的xml一起复制出来,接下来是unity篇了,先将这两个文件放到之前unity里面建好的Plugins/android下面,然后编辑这两个文件。
首先是xml文件,将xml的application<中添加打包后的包名,之前一直被这里坑>,设置完后保存关掉

然后用压缩工具打开aar文件,这里面的相对复杂点,首先将libs下的class.jar文件删除掉,因为这个是重复的

然后将androidmanifest.xml也删掉,外面已经有一个了

然后再双击打开这包里面的class.jar,找到最下级目录,删掉BuildConfig.class,这个在unity打包时会起冲突的,改完后然后关掉就好了,然后就是关于unity去掉用android部分了,看下面代码

using UnityEngine;
using System.IO;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.Networking;
using UnityEngine.Video;
using UnityEngine.Android;

public class GetAndroidPhoto : MonoBehaviour
{
    public Button button;
    public RawImage rawImage;

    void Start ()
    {
        button.onClick.AddListener(OpenLibery);
        Permission.RequestUserPermission(Permission.ExternalStorageRead);
        Permission.RequestUserPermission(Permission.ExternalStorageWrite);
    }

    private void OpenLibery()
    {
        AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
        jo.Call("TakePhoto", Application.persistentDataPath);
    }

    public void GetPhoto(string path)
    {
        Debug.Log("android give path ==> " + path);
        FileGetTex(path);
    }

    private void FileGetTex(string path)
    {
        FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
        fileStream.Seek(0, SeekOrigin.Begin);
        byte[] bye = new byte[fileStream.Length];
        fileStream.Read(bye, 0, bye.Length);
        fileStream.Close();

        Texture2D texture2D = new Texture2D((int)rawImage.rectTransform.rect.width, (int)rawImage.rectTransform.rect.height);
        texture2D.LoadImage(bye);
        rawImage.texture = texture2D;
    }
    public IEnumerator DownloadTexture(string url, RawImage rawImage)//这些都可以
    {
        using (UnityWebRequest request = UnityWebRequestTexture.GetTexture("file://" + url))
        {
            yield return request.SendWebRequest();

            if (request.error == null)
            {
                Texture2D texture = (request.downloadHandler as DownloadHandlerTexture).texture;
                rawImage.texture = texture;
            }
        }
    }
}

复制完代码后,将脚本拖到场景中指定的物体上,上面有提到过的呦,跟java代码里的名称设置一至才能调用
放置完后,创建canvas这些就不写,将脚本需要拖拽赋予的都放上去就KO了,然后就可以打包了,这里还有坑,那就是打包设置的Build System必须要设置为Gradle模式,否则会打包失败,而且即使选了也不一定能打包。。。。。,因为Gradle模式打包需要下载一些包,而软件本身的下载路径为国外的,所以你懂得,首先直接找到Unity2018.3.8\Unity2018\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\GradleTemplates路径,路径下有三个gradle后缀文件,都打开,然后找到有repositories块的就在里面添加下面这行代码

maven{ url 'http://maven.aliyun/nexus/content/repositories/central/'}

改完后再用Gradle模式打包,基本就KO了,测试打开相册KO,其实打开相册选图片和视频都一样,都是返回路径,然后unity里根据路径去获取,所以要相册的读写权限,可能不一定所有都成功,我的是2018.3.8版就KO,第一次写,有点渣,请见谅…狗头

生活不易,且行且珍惜,让自己每天过的充实些
如需转载请注明出处,码字也不易,谢谢!

本文标签: 相册 图片 视频 unity Android