实现保存截图至相册、显示Toast、打开相册选择头像裁剪并保存至持久化目录、打开相机拍照裁剪并保存至持久化目录、震动等功能
image.png
image.png
image.png
image.png
package com.packagename.aarlibrary;
import static com.unity3d.splash.services.core.misc.Utilities.runOnUiThread;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
import com.unity3d.player.UnityPlayer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class AndroidNativeBridge {
private static AndroidNativeBridge instance;
public String gameobject;
public static final int PHOTO_REQUEST_CODE = 108;//打开相册
public static final int PHOTO_CUTOUT_CODE=109;//裁剪截取 结果码
public static final int PHOTOHRAPH = 200;// 打开拍照
public static AndroidNativeBridge getInstance()
{
if(instance==null)
{
instance=new AndroidNativeBridge();
}
return instance;
}
public void Android_OnInit(String obj)
{
gameobject=obj;
}
//给U3D调用的打开相册
public void Android_OpenAlbum() {
//Intent就是应用之间,应用不同Activity之间交互。ACTION_GET_CONTENT ACTION_PICK
Intent getAlbum = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); //新建Intent,让用户选择特定类型的数据,并返回该数据的URI.
getAlbum.setType("image/*"); //类型为图片
UnityPlayer.currentActivity.startActivityForResult(getAlbum, PHOTO_REQUEST_CODE); //调用相册,结果码108,如果有结果会返回108,这个值随便设置,只要>=0就行
}
//打开相机
public void Android_OpenCamera()
{
Log.i("Unity", "打开相机" );
// String takephotoPath = Environment.getExternalStorageDirectory()+"/Android/data/com.Bitbuilding.DigitalRoomU3D/headImage.jpg";
// File destFile = new File(takephotoPath);
// if (destFile.exists()) {
// destFile.delete();
// }
//
// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Uri uri = Uri.parse("file://" + takephotoPath);
// intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
// UnityPlayer.currentActivity.startActivityForResult(intent, PHOTOHRAPH);
}
//显示土司
public void Android_ShowToastMessage(String msg)
{
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(UnityPlayer.currentActivity,msg,Toast.LENGTH_SHORT).show();
}
});
}
//保存到相册
public void Android_SaveToAlbum(String filePath, String str) {
if(str == null)
str = "已保存到相册";//设置保存成功的提示内容.
Toast.makeText(UnityPlayer.currentActivity, str, Toast.LENGTH_SHORT).show();
Log.i("Unity", "------------filePath" + filePath);//打印保存文件路径日志
SaveImageToGallery(filePath);
// Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
// scanIntent.setData(Uri.fromFile(new File(filePath)));
// UnityPlayer.currentActivity.sendBroadcast(scanIntent);
}
//震动
public void Android_Vibrate(long duration, float frequency)
{
if (duration <= 0 || frequency <= 0)
{
Log.e("error","Invalid parameters");
return;
}
long[] pattern = { 0, (long)(duration / 2f), (long)(1000f / frequency)};
Vibrator vibrator = (Vibrator) UnityPlayer.currentActivity.getSystemService(UnityPlayer.currentActivity.VIBRATOR_SERVICE);
if (vibrator.hasVibrator()) {
vibrator.vibrate(VibrationEffect.createWaveform(pattern, -1));
}
}
private void SaveImageToGallery(String imagePath) {
// Create a new image file in the DCIM/Camera folder
String timestamp = String.valueOf(System.currentTimeMillis());
String filename="image-"+timestamp+".jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/Camera");
Uri externalContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver resolver =UnityPlayer.currentActivity.getContentResolver();
Uri insertUri = resolver.insert(externalContentUri, values);
// Save the image file as JPEG format
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
try (OutputStream out = resolver.openOutputStream(insertUri)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
// Notify the MediaScanner about the new file so that it is immediately available in the Gallery app
String[] paths = { insertUri.getPath() };
String[] mimeTypes = { "image/jpeg" };
MediaScannerConnection.scanFile(UnityPlayer.currentActivity, paths, mimeTypes, null);
}
}
创建UnityActivityExtension.java文件继承UnityPlayerActivity
package com.packagename.aarlibrary;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class UnityActivityExtension extends UnityPlayerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
//重写Activity里的onActivityResult方法,这个方法和startActivityForResult是一对出现。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Log.d("onActivityResult回调","回调onActivityResult");
// 用户没有进行有效的设置操作,返回系统固定的常量RESULT_CANCELED=0
if (resultCode == RESULT_CANCELED) {
Toast.makeText(UnityPlayer.currentActivity, "没有选择图片", Toast.LENGTH_LONG).show();
return;
}
switch (requestCode) {
case AndroidNativeBridge.PHOTO_REQUEST_CODE:
//Toast.makeText(UnityPlayer.currentActivity, "图片挑选完成", Toast.LENGTH_LONG).show();
//裁剪图片
CropPhoto(intent.getData());//获取资源的Uri,安卓Uri通用资源标识符,表示一个图片或视频
break;
case AndroidNativeBridge.PHOTO_CUTOUT_CODE:
//Toast.makeText(UnityPlayer.currentActivity, "图片裁剪完成", Toast.LENGTH_LONG).show();
//保存图片
//可能抛出异常方法IOException方法必须用Try
try {
SaveImage(intent);
} catch (IOException e) {
e.printStackTrace();
}
break;
case AndroidNativeBridge.PHOTOHRAPH:
UnityPlayer.UnitySendMessage(AndroidNativeBridge.getInstance().gameobject, "OpenAlbum_Callback", "headImage.png");
break;
}
super.onActivityResult(requestCode, resultCode, intent);
}
//裁剪图片
public void CropPhoto(Uri uri) {
//调用裁剪器
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
// 开启裁剪功能
intent.putExtra("crop", "true");
//设置宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
//裁剪图片宽高
intent.putExtra("outputX", 100);
intent.putExtra("outputY", 100);
//请求返回数据
intent.putExtra("return-data", true);
UnityPlayer.currentActivity.startActivityForResult(intent, AndroidNativeBridge.PHOTO_CUTOUT_CODE); //结果码109
}
//保存裁剪图片供U3D读取 使用 FileOutputStream 必须要捕获和处理错误 抛出异常IOException
private void SaveImage(Intent intent) throws IOException {
//获取intent传过来的数据
//Bundle类是键值对形式,传递数据 Intent也可以传递数据,两个区别:intent是Bundle的封装
//Intent主要数据传递用,bundle主要存取数据用。
Log.d("b","保存裁剪后的图像SaveImage");
Bundle extras = intent.getExtras();
//取出数据
Bitmap bitmap = extras.getParcelable("data");
//文件路径=U3D里的Application.persistentDataPath路径 com.packagename.www为Unity工程中的的包名
File destDir = new File("/storage/emulated/0/Android/data/com.packagename.www/files");
//如果没有这个目录,创建一个
if (!destDir.exists()) {
destDir.createNewFile();
}
try {
Log.d("c","创建文件输出流");
//创建图片数据输出流 com.packagename.www为Unity工程中的的包名
FileOutputStream bitmapOut = new FileOutputStream("/storage/emulated/0/Android/data/com.packagename.www/files/headImage.png");
Log.d("c","压缩图片");
//压缩图片 参数1:图片格式 参数2:压缩率100表示不压缩 参数3:写入输出流
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bitmapOut);
//讲输出流刷新写出到磁盘
bitmapOut.flush();
//关闭流
bitmapOut.close();
Log.d("c","调用Unity函数AndroidSaveHeadImageOver");
//通知U3D可以读取图片了 参数1:U3D物体名称 参数2:方法名 参数3:要传递的参数,这里传图片名称
UnityPlayer.UnitySendMessage(AndroidNativeBridge.getInstance().gameobject, "OpenAlbum_Callback", "headImage.png");
}catch (Exception e){
e.printStackTrace();
}
}
}
选择库然后Make一下image.png
image.png
image.png
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.packagename.aarlibrary.UnityActivityExtension"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:theme="@style/UnityThemeSelector" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="unityplayer.UnityActivity"
android:value="true" />
</activity>
</application>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE" />
</manifest>
Unity中创建脚本NativeAndroidImpl.cs
using UnityEngine;
namespace com.nativesdk.unity3d
{
#if UNITY_ANDROID && !UNITY_EDITOR
public class NativeAndroidImpl : NativeSDKImpl
{
private AndroidJavaClass jc;
private AndroidJavaObject jo;
public NativeAndroidImpl(string obj)
{
jc = new AndroidJavaClass("com.bitbuilding.digitalroom.aarlibrary.AndroidNativeBridge");
if (jc != null)
jo = jc.CallStatic<AndroidJavaObject>("getInstance");
if (jo != null)
jo.Call("Android_OnInit", obj);
}
public override void SaveToAlbum(string filePath, string tip)
{
if (jo != null)
jo.Call("Android_SaveToAlbum", filePath, tip);
}
public override void OpenAlbum()
{
if (jo != null)
jo.Call("Android_OpenAlbum");
}
public override void OpenCamera()
{
if (jo != null)
jo.Call("Android_OpenCamera");
}
public override void ShowToastMessage(string message)
{
if (jo != null)
jo.Call("Android_ShowToastMessage", message);
}
public override void OnVibrator(long time, float hz)
{
jo.Call("Android_Vibrate", time, hz);
}
}
#endif
}
using System;
namespace com.nativesdk.unity3d
{
public abstract class NativeSDKImpl
{
/// <summary>
/// 显示Toas消息
/// </summary>
/// <param name="msg"></param>
public abstract void ShowToastMessage(string message);
/// <summary>
/// 保存入相册
/// </summary>
/// <param name="filePath"></param>
/// <param name="tip"></param>
public abstract void SaveToAlbum(string filePath, string tip);
/// <summary>
/// 打开原生相册UI
/// </summary>
public abstract void OpenAlbum();
/// <summary>
/// 打开原生相机
/// </summary>
public abstract void OpenCamera();
/// <summary>
/// 震动
/// </summary>
/// <param name="time">持续时长</param>
/// <param name="hz">震动频率 HZ</param>
public abstract void OnVibrator(long time, float hz);
}
}