Unity调用Android相册
最近有一个项目有这个需求,让用户上传自己的交易凭证的截图,之前因为对调Android原生的东西不太熟悉,就先放了一边
因为项目已经上线,只不过是该功能未开放而已,那么现在为什么要写这篇博客呢,是因为........因为最近有客户产生交易申诉,也就是两方交易,一个说我给钱了,另一个说我没收到钱
这样的情况下,这个功能就显得很重要了,于是立马开始着手这个功能的开发
虽然说网上一搜一大把源码,可是几乎每一个能用的,于是放弃,还是自己研究吧,这个过程踩过无数坑,掉了无数发,流了无数泪
PS:后面会说调IOS相册的,因为我们的项目都不可能只有Android或者只有IOS的吧,这里说一个小插曲,也是这个插曲使我决定了先写调Android相册原因 π_π
我花了两天时间,看了无数教程,终于把调Android的demo写好了,然后就开始写ios 的,又用了两天把ios的研究好了写完demo了,回过头来发现之前Android的demo包又不能用了,真是玄学
有时候开发这个东西,你不信玄学还真是不行,于是重头又写了一遍,还是不行,于是又开始研究,终于搞定,这篇文章涉及到C#,java,Unity,AndroidStudio,还是建议有些基础的人看,好了,下面步入正题
这篇文章会很长,因为我会把自己踩过的坑详细的说清楚是怎么解决的
逻辑:Unity调用Android的方法,打开相册,选中图片后Android将图片路径作为参数,调用Unity的方法,然后在Unity里加载图片出来
一、准备jar包,供Unity使用
Unity和Android交互,这个jar包就是一个中间商,也就是说,我们获取相册里的相片路径,并告知Unity这个路径,这一部分功能在安卓端实现
(1)androidstudio新建工程,这一系列没有什么好说的,新建一个空工程,值得注意是下图圈起来的两个地方,packagename==>这个必须要和你的Unity工程的包名一样,
不然打出来的包安装完成后会闪退的,还有就是最低支持的API等级,这个也必须和Unity里面的buildsetting里面的对应
(2)接下来在MainAcitivy里面复制我下面的代码,这里要注意在复制代码的时候,第一行是包名,这里被我删了,因为每个人包名都不一样,包名需要保留,不能没有
之后你会发现TakePhoto是灰色的,不用管它,这个Unity调用android的入口,这个函数名要是改了话,Unity的C#代码也需要改对应的,不然调不到
然后你还会发现WebViewActivity和UnityPlayerActivity报错,先别慌,稳住,看下一步!
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);
} }
(3)导入Unity的classes.jar
先说这个文件在哪,在你所使用的Unity的安装目录里面,这里需要注意呀,不是什么版本的Unity的这个classes.jar都能用的,必须是你Unity工程所使用的版本的安装目录
将这个jar包赋值一份,并拷贝到刚才新建的Android项目的app\libs文件夹里点击左上角的Android图片,切换到project视图就能找到这个文件夹
然后右键这个classes.jar,选择add as library,会弹出一个框,确定是给app添加的就行,确定后等待编译一会,UnityPlayerActivity就会正常了,这是因为Android需要和Unity通信,就必须得调用Unity的类才行
(4)创建WebViewActivity类,切换回Android视图找到我们的MainActivty,这个都会在app\java\第一个包名的文件夹下
然后右键,new一个javaclass,命名就是WebViewActivity,创建的时候什么都不用管,都是默认就行
然后你就会看到什么报错都没了,接下来把下面的代码复制到WebViewActivity,这里还是一样不能自己的包名给粘贴调哈
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 android.view.KeyEvent; import com.unity3d.player.UnityPlayer; import java.io.IOException; public class WebViewActivity extends Activity
{
public static final int NONE = 0; public static final int PHOTORESOULT = 3; public static final String IMAGE_UNSPECIFIED = "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)
return; if (data == null)
return; 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("Main Camera", "GetPhoto", _path); super.onActivityResult(requestCode, resultCode, data); this.finish();
}
}
这里需要注意的地方
这是调用Unity的main camera 上的脚本里的Getphoto方法,path是传递过去的参数
unity里面需要在什么地方加这个功能,以及脚本挂载什么对象身上,这些都要先考虑好之后才能打这个jar包,到这里第一阶段Android的功能已经写完了,接下来就是打包了,坑较多,一定要注意了
(5)准备打jar包,新建module file - new - new module - Android Library - next 这里的packagename和最小版本sdk也要设置一下和上面的一样
然后之前写的两个脚本复制到你新建的module的同样的位置,然后切换到project视图,将app\libs里面的classes.jar也复制到new module的libs里面,然后一样的add as library,一样的注意跟Unity一样的包名
(6)编辑new module的Androidmanifest.xml,复制一下代码粘贴就行,注意包名是自己的,在这里加相册权限,包名和unity的不一样的话,到时候unity打出来apk会闪退
之后打完包之后 这个xml文件需要和打出来的jar包一起放到Unity工程里面的
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.NXNC.Farm" >
<!--读取相册权限 (必须)-->
<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>
(7)在build.gradle中加上一下代码,这里注意,这个build.gradle是你新建module的build.gradle
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)
这里的坑就是from,有不同的位置,但是基本都是这个目录,如果你最后发现你打包成功之后,却发现没有包,就是这个地方错了
(8)打jar包,这里也是坑最多的地方,网上的解决方法也是五花八门
打包之前建议:
先在Androidstudio的安装目录的bin文件夹下找到studio.exe.vmoptions或者studio64.exe.vmoptions,看你是32位还是64的,就编辑哪个,按如下编辑
gradle.properties注释掉org.gradle.jvmrgs这句话,也许值会不一样,反正注释掉就行
然后就可以打包了
在Terminal里面输入命令 gradlew makejar 等一会就会提示build successful 这就是包打好了
左上角切换回project视图,在新建module的libs里面就会有新的jar,这个就是我们需要的
最后我们需要的两个东西 就是这个打出来jar和new module的AndroidManifest文件,复制到Unity里面
二、Unity调用
(1)unity工程asset文件下新建文件夹plugins-Android,然后AndroidManifest和jar包放入就行
奉上demo脚本
using UnityEngine;
using System.IO;
using UnityEngine.UI; public class GetAndroidPhoto : MonoBehaviour
{
public Button button;
public RawImage rawImage; void Start ()
{
button.onClick.AddListener(OpenLibery);
} 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(, SeekOrigin.Begin);
byte[] bye = new byte[fileStream.Length];
fileStream.Read(bye, , bye.Length);
fileStream.Close(); Texture2D texture2D = new Texture2D((int)rawImage.rectTransform.rect.width, (int)rawImage.rectTransform.rect.height);
texture2D.LoadImage(bye);
rawImage.texture = texture2D;
}
}
TakePhoto、GetPhoto分别和Android工程里的对应的,这里还有一个很玄学的问题,我使用的加载图片试过了www,试过了http,就是不行,最后只能通过文件流的方式加载
写完demo是不能直接在unity运行的,要打出apk真机测试
三、Unity gradle模式下打包apk
(1)检查buildsetting - playersetting - other setting的packagename是否与AndroidManifest里面的一直,不一样的就恭喜自己,要么unity改包名,要么改Android工程,从头再来
(2)检查build setting的build system,一定要是Gradle,因为我们需要与Android交互,就必须选这个,这里埋个坑,就是我们打好的jar现在还不能直接放到unity里打测试包的,会报错的
但是你选internal这个包就能顺利打出来,但是这样放到正式工程中你就不能签名了,所以当你打包出错,并报错
CommandInvokationFailure: Gradle build failed.
C:/Program Files (x86)/Java/jdk1.8.0_73\bin\java.exe -classpath "C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-4.2.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx1024m" "assembleRelease"
stderr[
Dex: Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Lcom/NXNC/Farm/BuildConfig;
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Lcom/NXNC/Farm/BuildConfig;
at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:660)
at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:615)
at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:597)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:170)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:197)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:503)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:333)
at com.android.dx.command.dexer.Main.runDx(Main.java:288)
at com.android.dx.command.dexer.Main.main(Main.java:244)
at com.android.dx.command.Main.main(Main.java:95)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':transformDexWithDexForRelease'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException: Error while executing java process with main class com.android.dx.command.Main with arguments {--dex --num-threads=4 --output E:\MX\Project\Unity\TestFarmPhotoFinally\Temp\gradleOut\build\intermediates\transforms\dex\release\0 --min-sdk-version 16 E:\MX\Project\Unity\TestFarmPhotoFinally\Temp\gradleOut\build\intermediates\transforms\preDex\release\0.jar E:\MX\Project\Unity\TestFarmPhotoFinally\Temp\gradleOut\build\intermediates\transforms\preDex\release\3.jar E:\MX\Project\Unity\TestFarmPhotoFinally\Temp\gradleOut\build\intermediates\transforms\preDex\release\2.jar}
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
* Get more help at https://help.gradle.org
BUILD FAILED in 11s
]
stdout[
Starting a Gradle Daemon (subsequent builds will be faster)
Observed package id 'tools' in inconsistent location 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\toolsOLD' (Expected 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\tools')
Already observed package id 'tools' in 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\tools'. Skipping duplicate at 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\toolsOLD'
Observed package id 'tools' in inconsistent location 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\toolsOLD' (Expected 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\tools')
Already observed package id 'tools' in 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\tools'. Skipping duplicate at 'E:\SDK\android-sdk-windows2017-12-25 (1)\android-sdk-windows2017-12-25\toolsOLD'
:preBuild UP-TO-DATE
:preReleaseBuild UP-TO-DATE
:compileReleaseAidl UP-TO-DATE
:compileReleaseRenderscript UP-TO-DATE
:checkReleaseManifest UP-TO-DATE
:generateReleaseBuildConfig UP-TO-DATE
:prepareLintJar UP-TO-DATE
:generateReleaseResValues UP-TO-DATE
:generateReleaseResources UP-TO-DATE
:mergeReleaseResources UP-TO-DATE
:createReleaseCompatibleScreenManifests UP-TO-DATE
:processReleaseManifest
:splitsDiscoveryTaskRelease UP-TO-DATE
:processReleaseResources
:generateReleaseSources
:javaPreCompileRelease
:compileReleaseJavaWithJavac UP-TO-DATE
:compileReleaseNdk NO-SOURCE
:compileReleaseSources UP-TO-DATE
:lintVitalRelease
:mergeReleaseShaders UP-TO-DATE
:compileReleaseShaders UP-TO-DATE
:generateReleaseAssets UP-TO-DATE
:mergeReleaseAssets
:transformClassesWithPreDexForRelease
:transformDexWithDexForRelease
Running dex as a separate process.
To run dex in process, the Gradle daemon needs a larger heap.
It currently has 1024 MB.
For faster builds, increase the maximum heap size for the Gradle daemon to at least 1536 MB.
To do this set org.gradle.jvmargs=-Xmx1536M in the project gradle.properties.
For more information see https://docs.gradle.org/current/userguide/build_environment.html
:transformDexWithDexForRelease FAILED
20 actionable tasks: 7 executed, 13 up-to-date
]
exit code: 1
UnityEditor.Android.Command.WaitForProgramToRun (UnityEditor.Utils.Program p, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
UnityEditor.Android.Command.Run (System.Diagnostics.ProcessStartInfo psi, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
UnityEditor.Android.AndroidJavaTools.RunJava (System.String args, System.String workingdir, System.Action`1[T] progress, System.String error) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, System.String workingdir, System.String task, System.Action`1[T] progress) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
Rethrow as GradleInvokationException: Gradle build failed
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, System.String workingdir, System.String task, System.Action`1[T] progress) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
UnityEditor.Android.PostProcessor.Tasks.BuildGradleProject.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <fdd3823527dc4dde8316302bb5a76d3b>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
网上会推荐你讲gradle 换成 internal ,这个建议纯属一派胡言,这并不是解决问题,而是绕过了问题,坚决不能采取这个!!!!!!!
会说你的Android工程的内存分配不够 更会说jdk sdk ndk版本不对,也许你试过一大圈之后发现并没有用,我在这里卡了整整两天,最后......
我的解决方案:
用压缩包打开我们的jar,然后删掉里面的buildconfig.class,最后顺利解决,gradle模式下打包成功,demo在手机上成功运行
这是因为Unity打包编译的时候也会生成这个文件,和包里面的冲突了
Unity调用Android相册的更多相关文章
- Unity调用Android类方法
Unity调用Android类方法 1. 添加Unity的classes.jar文件 创建一个Android工程AndroidUnityDemo. 由于Unity的版本不同,直接在Unity安装包文 ...
- unity 调用android函数
unity 调用android函数 分类: unity2013-12-19 17:54 475人阅读 评论(0) 收藏 举报 unityandroidjar 我们知道,安卓project都有一个And ...
- Unity调用Android
1.Unity调用Android 根据unity用户手册,unity可以采用native code(c/c++),但是也提供了C#调用方法,本文对此进行简单讲解. 2.Unity获取android类 ...
- Andriod Unity 调用android函数
//首先这是一个前沿 //我看了多的资料,还看了近半个小时的 android activity 的讲解 终于打出了apk //接下来开始 //一步一步的跟着我走 1.创建一个android项目或者一个 ...
- Unity 调用android插件
1. Unity的Bundle Identifier必须和你的android报名一致 Activity和View的区别: Activity应该是一个展示页面,View是页面上一些按钮视图等等. 如何调 ...
- Unity调用Android的两个方式:其一、调用jar包
unity在Android端开发的时候,免不了要调用Java:Unity可以通过两种方式来调用Android:一是调用jar.二是调用aar. 这篇文章主要讲解怎么从无到有的生成一个jar包,然后un ...
- unity调用Android百度地图
由于个人是Android小白,在这个配置上面被折磨了很久,因此写下这篇文章 工具:eclipse + unity5.6.1 首先去百度地图开发者平台下载你需要的资源,我只需要显示地图和定位,这个时候你 ...
- unity调用Android的jar包
简介 有一些手机功能,Unity没有提供相应的接口,例如震动,例如不锁屏,例如GPS,例如... 有太多的特殊功能Unity都没有提供接口,这时候,我们就需要通过使用Android原生的ADT编辑器去 ...
- unity调用Android的两种方式:其二,调用aar包
上一篇我们讲了unity如何调用jar包 http://www.cnblogs.com/Jason-c/p/6743224.html, 现在我们介绍一下怎么生成aar包和unity怎么调用aar 一. ...
随机推荐
- 3D漫游的分类 3D Navigation Taxonomy
在2001年CHI发表的论文中1,Tan等人提出了一种对3D漫游的分类方法. 当时关于3D漫游(3D Navigation)的研究主要分为两种:一种是发掘有关漫游的认知原则,一种是开发一些具体的漫游技 ...
- InfluxDB从原理到实战 - 什么是InfluxDB
0x00 什么是InfluxDB InfluxDB是一个由InfluxData开发的开源时序型数据库,专注于海量时序数据的高性能读.高性能写.高效存储与实时分析等,在DB-Engines Rankin ...
- Python PDB调试处理
pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点.单步调试.进入函数调试.查看当前代码.查看栈片段.动态改变变量的值等.pdb 提供了 ...
- 【Java】访问mysql数据库视图
数据库连接Connect: package cn.hkwl.zaxq.mysql; import java.sql.Connection; import java.sql.DriverManager; ...
- [ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker
对于一个 .NET Core开发人员,你可能没有使用过Docker,但是你不可能没有听说过Docker.Docker是Github上最受欢迎的开源项目之一,它号称要成为所有云应用的基石,并把互联网升级 ...
- 编程杂谈——使用emplace_back取代push_back
近日在YouTube视频上看到关于vector中emplace_back与push_back区别的介绍,深感自己在现代C++中还是有不少遗漏的知识点,遂写了段代码,尝试比较两者的差别. 示例代码 #i ...
- BZOJ 1965 [AHOI2005]洗牌
题目描述 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动. 由于Samuel星球相当遥远,科学家们要在飞船中度过相当长的一段时间,小联提议用扑克牌打 ...
- 复杂模型可解释性方法——LIME
一.模型可解释性 近年来,机器学习(深度学习)取得了一系列骄人战绩,但是其模型的深度和复杂度远远超出了人类理解的范畴,或者称之为黑盒(机器是否同样不能理解?),当一个机器学习模型泛化性能很好时 ...
- 超级好用的c#解析JSON
分享c# 一款非常好用的操作Json的dll,litjson VS2017 NuGet 搜索litjson,如下图: 例子: 在项目中新建一个txt文本文件,内容如下: [ { , "use ...
- powershell(一)
Windows powershell是一种命令行外壳程序和脚本环境,它内置在win7以上版本的操作系统中,使命令行用户和脚本编写者可以利用.NET Framework的强大功能.powershell程 ...