Unity与安卓交互(打开安卓手机相册为例)

tech2022-09-01  121

Unity与安卓交互 记录贴,提问帖

创建两个类更新: 看了下方你能学到基础的安卓API自己关于安卓方面也不会再感到迷茫,我会仔细解释相关API,我们以上方的例子为基础加以修改

创建两个类

更新: 看了下方你能学到基础的安卓API自己关于安卓方面也不会再感到迷茫,我会仔细解释相关API,我们以上方的例子为基础加以修改

第一步:在上方工程中重新建一个Mold并选择AndroidLibrary(记住打出的Arr包即插件名称将默认为该名称) 这是我新建的AndroidLibrary直接将上方这两java文件以及Unity的lib‘文件复制到对应目录.提示可以直接 :“Ctrl + c 和Ctrl + v ” 对CallAndroid类进行修改去掉多余的行为 import android.app.Activity; import android.content.Intent; import com.unity3d.player.UnityPlayer; public class CallAndroid { //Unity中会调用这个方法,用于打开本地相册 //str 为unity传过来的路径 public void TakePhoto(String str)//我们不需要unity传它的上下文 可以直接通过UnityPlayer.currentActivity获取Unity的界面(Activity) { System.out.println("路径:"+str); Intent intent = new Intent(UnityPlayer.currentActivity,WebViewActivity.class);//WebViewActivity为需要跳转的界面(Activity) //记得回来修改这里WebViewActivity改为权限的Activity我这里是TestActivity intent.putExtra("path", str);//传给跳转的Activity 参数一是键 参数二是值 UnityPlayer.currentActivity.startActivity(intent);//跳转到另一个界面(Activity) } } 动态权限部分:安卓6.0后有了动态权限(即需要向用户申请权限)而且 我们不希望游戏一打开就提示用户给予权限 所有我们现在的需求就是在调用时先判断用户是否给予了对应权限 大家可以自己网上找一些写的好的我这里给大家提供一个博主写的,感觉很不错 “我找不到那篇博客了如果找到了会贴上地址的” package com.jing.pickpicture.permission; import android.app.Activity; import android.content.pm.PackageManager; import android.os.Build; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; /** * @author Admin * @version $Rev$ * @des ${TODO} * @updateAuthor $Author$ * @updateDes ${TODO} */ public class BasePermission extends Activity { //**************** Android M Permission (Android 6.0权限控制代码封装) private int permissionRequestCode = 88; private PermissionCallback permissionRunnable; public interface PermissionCallback { void hasPermission(); void noPermission(); } /** * Android M运行时权限请求封装 * * @param permissionDes 权限描述 * @param runnable 请求权限回调 * @param permissions 请求的权限(数组类型),直接从Manifest中读取相应的值,比如Manifest.permission.WRITE_CONTACTS */ @RequiresApi(api = Build.VERSION_CODES.M) public void performCodeWithPermission(@NonNull String permissionDes, PermissionCallback runnable, @NonNull String... permissions) {//子类调用 if (permissions == null || permissions.length == 0) return; // this.permissionrequestCode = requestCode; this.permissionRunnable = runnable; if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.M) || checkPermissionGranted(permissions)) {//安卓api小于26或者已经授权 直接调用子类传来的PermissionCallback接口hasPermission函数 if (permissionRunnable != null) { permissionRunnable.hasPermission(); permissionRunnable = null; } } else {// //permission has not been granted. requestPermission(permissionDes, permissionRequestCode, permissions);//申请权限 } } @RequiresApi(api = Build.VERSION_CODES.M) private boolean checkPermissionGranted(String[] permissions) { boolean flag = true; for (String p : permissions) { if ( checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED) {//调用继承自Activity的checkSelfPermission函数判断是否已经授权 flag = false; break; } } return flag; } @RequiresApi(api = Build.VERSION_CODES.M) private void requestPermission(String permissionDes, final int requestCode, final String[] permissions) { if (shouldShowRequestPermissionRationale(permissions)) { /*1. 第一次请求权限时,用户拒绝了,下一次:shouldShowRequestPermissionRationale() 返回 true,应该显示一些为什么需要这个权限的说明 2.第二次请求权限时,用户拒绝了,并选择了“不在提醒”的选项时:shouldShowRequestPermissionRationale() 返回 false 3. 设备的策略禁止当前应用获取这个权限的授权:shouldShowRequestPermissionRationale() 返回 false*/ // Provide an additional rationale to the user if the permission was not granted // and the user would benefit from additional context for the use of the permission. // For example, if the request has been denied previously. // Snackbar.make(getWindow().getDecorView(), requestName, // Snackbar.LENGTH_INDEFINITE) // .setAction(R.string.common_ok, new View.OnClickListener() { // @Override // public void onClick(View view) { // ActivityCompat.requestPermissions(BaseAppCompatActivity.this, // permissions, // requestCode); // } // }) // .show(); //如果用户之前拒绝过此权限,再提示一次准备授权相关权限 requestPermissions( permissions, requestCode); /* new AlertDialog.Builder(this) .setTitle("提示") .setMessage(permissionDes) .setPositiveButton("授权", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { requestPermissions( permissions, requestCode); } }).show();*/ } else { // Contact permissions have not been granted yet. Request them directly. requestPermissions( permissions, requestCode);// 调用Activity父类中继承下的requestPermissions方法进行授权 requestCode 随意 这里是上方字段permissionRequestCode 88 调用该方法会跳转到权限授予Activity(界面) //并且无论你在授予权限确定还是取消都会调用下方 onRequestPermissionsResult函数 } } @RequiresApi(api = Build.VERSION_CODES.M) private boolean shouldShowRequestPermissionRationale(String[] permissions) { boolean flag = false; for (String p : permissions) { if ( shouldShowRequestPermissionRationale( p)) {//遍历所有传来的权限调用Activity父类中继承下的shouldShowRequestPermissionRationale方法判断是否向用户显示授予该权限原因 flag = true; break; } } return flag; } /** * Callback received when a permissions request has been completed. */ @Override//参数一是 我们requestPermissions函数传的 permissions也就是上方字段permissionRequestCode 88 参数二 是我们申请的权限 参数3是申请结果 PERMISSION_DENIED = -1(否定);PERMISSION_GRANTED = 0(确定); public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == permissionRequestCode) { //这里的 permissionRequestCode暂时 没什么作用 因为是上面调用传的88 所以这里依旧是88 if (verifyPermissions(grantResults)) { if (permissionRunnable != null) { permissionRunnable.hasPermission(); permissionRunnable = null; } } else { Toast.makeText(this, "暂无权限执行相关操作!", Toast.LENGTH_SHORT).show(); if (permissionRunnable != null) { permissionRunnable.noPermission(); permissionRunnable = null; } } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } public boolean verifyPermissions(int[] grantResults) { // At least one result must be checked.performCodeWithPermission if (grantResults.length < 1) { return false; } // Verify that each required permission has been granted, otherwise return false. for (int result : grantResults) {//遍历结果 if (result != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } //********************** END Android M Permission **************************************** }

我们自己建一个类继承它 :大家记得回去修改跳转的类因为我们在调用选择图片时因该先判断是否获取了权限

package com.jing.pickpicture.permission; import android.Manifest; import android.content.Intent; import android.os.Build; import android.os.Bundle; import androidx.annotation.RequiresApi; import com.jing.pickpicture.WebViewActivity; public class TestActivity extends BasePermission implements BasePermission.PermissionCallback{ @RequiresApi(api = Build.VERSION_CODES.M) protected void onCreate(Bundle savedInstanceState) {//Activity方法 只有Activity(界面)被创建时会被调用比如被跳转时 super.onCreate(savedInstanceState); performCodeWithPermission("确认权限",this,new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}); } @Override public void hasPermission() {//BasePermission中接口PermissionCallback中的方法 System.out.println("已获取权限"); Intent intent = new Intent(this, WebViewActivity.class); //getIntent().getStringExtra("path") 通过键获取上文的值 这里是CallAndroid那里存入的值 intent.putExtra("path",getIntent().getStringExtra("path"));//继续把unity那边路径传入下个跳转的Activity startActivity(intent); finish();//销毁当前Activity } @Override public void noPermission() {//BasePermission中接口PermissionCallback中的方法 System.out.println("取消权限,返回游戏"); this.finish();//销毁当前Activity } @Override public void onResume() {//Activity方法 只有Activity(界面)被显示时调用 super.onResume(); System.out.println("返回到TestActivity"); } } `` 改一下 WebViewActivity ```java package com.jing.pickpicture; 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.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class WebViewActivity extends Activity { public static final int PHOTORESOULT = 3; public static final String IMAGE_UNSPECIFIED = "image/*"; private String FILE_NAME = "Photo.png"; private String phtoPath; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); phtoPath = getIntent().getStringExtra("path");//获取路径 Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED); intent.putExtra("return-data", true); startActivityForResult(intent, PHOTORESOULT);//以该函数跳转Activity会以onActivityResult来接受跳转Activity的结果 } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {//requestCode是我们在上方startActivityForResult的参数2(这里没起作用) resultCode是上一个Activity也就是选择图片的那个Activty(页面)的结果 if (resultCode == RESULT_CANCELED)//如果接收结果为返回 { finish(); return;} if (data == null)//上下文为空 { finish(); return;} ContentResolver resolver = getContentResolver(); Bitmap photo=null; Uri originalUri = data.getData(); try { photo = MediaStore.Images.Media.getBitmap(resolver, originalUri); } catch (IOException e) { e.printStackTrace(); } System.out.println("=="+photo); String fullPath = phtoPath+ "/" + FILE_NAME; FileOutputStream out = null; try { out = new FileOutputStream(new File(fullPath)); } catch (FileNotFoundException e) { e.printStackTrace(); } photo.compress(Bitmap.CompressFormat.PNG, 90, out);//压缩文件到指定路径 try { out.flush(); } catch (IOException e) { e.printStackTrace(); } try { out.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println("保存图片"); FileOutputStream fOut = null; System.out.println("返回游戏"); try { Intent intent = new Intent(this,Class.forName("com.unity3d.player.UnityPlayerActivity")); startActivity(intent);//返回Unity //这里也可以直接finish UnityPlayer.UnitySendMessage("Main Camera","CallBack",fullPath); return; } catch (ClassNotFoundException e) { e.printStackTrace(); } super.onActivityResult(requestCode, resultCode, data); this.finish(); } }

修改Build可以不用把Unity的jar包打入 最后把用到的Activity以及权限添加到安卓清单文件

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application > <activity android:name=".permission.TestActivity" /> <activity android:name=".WebViewActivity" /> </application>

Unity代码

using System.IO; using UnityEngine; using UnityEngine.UI; public class GetPhoto : MonoBehaviour { public Button Bt; public Image image; private void Start() { Bt.onClick.AddListener(() => { using (AndroidJavaObject javaobj = new AndroidJavaObject("com.jing.pickpicture.CallAndroid")) { javaobj.Call("TakePhoto",Application.persistentDataPath); } }); } private void CallBack(string fullPath) { byte[] datas = File.ReadAllBytes(fullPath); Texture2D texture = new Texture2D((int)image.rectTransform.rect.width, (int)image.rectTransform.rect.height); texture.LoadImage(datas); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)); image.sprite = sprite; } }

至于为啥是 AndroidJavaClass jc = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”); var jo = jc.GetStatic(“currentActivity”); 我们创建个新工程导出为安卓工程 然后贴上官方的解释

最新回复(0)