java代码 。CommonUtils.java
package com.cocos.common;
import android.Manifest;
import android.content.ClipData;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.cocos.game.AppActivity;
import com.cocos.lib.CocosHelper;
import com.cocos.lib.CocosJavascriptJavaBridge;
public class CommonUtils {
static CommonUtils s_common = null;
public static CommonUtils getInstance() {
if (s_common == null) {
s_common = new CommonUtils();
}
return s_common;
}
public static final int REQUEST_CODE_CAMERA = 110;
public static final int REQUEST_CODE_ALBUM = 111;
public static final int REQUEST_CODE_CROP = 112;
public static Integer clipX = 0;
public static Integer clipY = 0;
public static Integer needClip = 0;
public static Integer photoType = 1;
public static Uri uriClipUri = null;
public static Uri mCameraUri = null;
private static AppActivity instance = null;
public static void selectPhoto(String path, String info) {
s_common.useSystemAlbum(info);
}
public static void initComUtils(AppActivity context) {
s_common.instance = context;
}
/**
* 调用系统相册和裁剪
* @param info
*/
public static void useSystemAlbum(String info){
clipX = 0;
clipY = 0;
try{
JSONObject jsonObject = new JSONObject(info);
needClip = jsonObject.getInt("needClip");
clipX = jsonObject.getInt("clipX");
clipY = jsonObject.getInt("clipY");
}catch(Exception e){
e.printStackTrace();
}
pickImage();
}
/**
* 选择相册上传图片
*/
public static void pickImage(){
photoType = 1;
String[] needPermissions = new String[] {
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
List<String> permissionList = new ArrayList<>();
for (String permission : needPermissions) {
if (ActivityCompat.checkSelfPermission(instance, permission) != PackageManager.PERMISSION_GRANTED)
permissionList.add(permission);
}
if (permissionList.size() == 0) {
// Log.i("pickImg","已经获取到所有权限");
goPhotoAlbum();
}else{
String[] requestPermissions = permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(instance,requestPermissions, 1001);
}
}
public static void goPhotoAlbum(){
Intent intentAlbum= new Intent(Intent.ACTION_PICK, null);
//其中External为sdcard下的多媒体文件,Internal为system下的多媒体文件。
//使用INTERNAL_CONTENT_URI只能显示存储在内部的照片
intentAlbum.setDataAndType(
MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
//返回结果和标识
instance.startActivityForResult(intentAlbum, REQUEST_CODE_ALBUM);
}
// 处理图片路径4.4之后
private String handleImageOnKitkat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
imagePath = changeUriToPath(uri);
return imagePath;
}
private String changeUriToPath(Uri uri){
String imagePath = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (DocumentsContract.isDocumentUri(instance, uri)) {
//如果是document类型的uri,则通过document id 处理
String docId = DocumentsContract.getDocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())) {
//解析出数字格式的id
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID+ "=" +id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection );
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse
("content://downloads/public_downloads"),Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
//如果是content类型的uri,则用普通方式处理
imagePath = getImagePath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
//如果是file类型的uri,直接获取图片路径
imagePath = uri.getPath();
}
}
return imagePath;
}
//处理图片路径4.4之前
private String handleImageBeforeKitkat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
return imagePath;
}
private String getImagePath(Uri uri,String selection) {
String path = null;
//通过uri 和 selection 获取真实的图片路径
Cursor cursor = instance.getContentResolver().query(uri,null,selection,null,null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
/**
* 图片裁剪的方法
* @param uri
*/
public void startPhotoZoom(Uri uri) {
// Log.i("pickImg uri=====", "" + uri);
//com.android.camera.action.CROP,这个action是调用系统自带的图片裁切功能
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");//裁剪的图片uri和图片类型
intent.putExtra("crop", true);//设置允许裁剪,如果不设置,就会跳过裁剪的过程,还可以设置putExtra("crop", "circle")
intent.putExtra("aspectX", 1);//裁剪框的 X 方向的比例,需要为整数
intent.putExtra("aspectY", 1);//裁剪框的 Y 方向的比例,需要为整数
// intent.putExtra("outputX", 60);//返回数据的时候的X像素大小。
// intent.putExtra("outputY", 60);//返回数据的时候的Y像素大小。
if(clipX != 0 && clipY != 0){
intent.putExtra("OutputX", clipX);// 设置最终裁剪的宽和高
intent.putExtra("OutputY", clipY);// 设置最终裁剪的宽和高
// Log.i("pickImg","设置裁剪输出宽和高="+clipX+"-"+clipY);
}
//uriClipUri为Uri类变量,实例化uriClipUri
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (photoType == 2) {//如果是7.0的拍照
// //开启临时访问的读和写权限
// intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
// //针对7.0以上的操作
// intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri));
// uriClipUri = uri;
} else if(photoType == 1) {//如果是7.0的相册
//设置裁剪的图片地址Uri
uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" +"clip.jpg");
// Log.i("pickImg","android 7.0调用相册= "+uriClipUri);
}
} else {
uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg");
}
// Log.i("pickImg uriClipUri=====", "" + uriClipUri);
//Android 对Intent中所包含数据的大小是有限制的,一般不能超过 1M,否则会使用缩略图 ,所以我们要指定输出裁剪的图片路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriClipUri);
intent.putExtra("return-data", false);//是否将数据保留在Bitmap中返回
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//输出格式,一般设为Bitmap格式及图片类型
intent.putExtra("noFaceDetection", true);//人脸识别功能
instance.startActivityForResult(intent, REQUEST_CODE_CROP);//裁剪完成的标识
}
public static String bitmapToBase64(Bitmap bitmap) {
String result = null;
ByteArrayOutputStream baos = null;
try {
if (bitmap != null) {
baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 30, baos);
baos.flush();
baos.close();
byte[] bitmapBytes = baos.toByteArray();
result = Base64.encodeToString(bitmapBytes, Base64.NO_WRAP);
}
} catch (IOException e) {
e.printStackTrace();
Log.i("pickImg","io exception111");
} finally {
try {
if (baos != null) {
baos.flush();
baos.close();
}
} catch (IOException e) {
Log.i("pickImg","io exception222");
e.printStackTrace();
}
}
return result;
}
// @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// instance.onActivityResult(requestCode, resultCode, data);
// FaceBookLogin.callbackManager.onActivityResult(requestCode, resultCode, data);
// SDKWrapper.getInstance().onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE_ALBUM && resultCode == instance.RESULT_OK){
Log.i("pickImg ","调用相册回调");
if(data != null){
if(needClip == 1){
startPhotoZoom(data.getData());
return;
}
String filePath = null;
if (resultCode == instance.RESULT_OK) {
//判断手机的系统版本号
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//4.4系统的及以上用此方法处理照片
filePath = handleImageOnKitkat(data);
} else {
// 4.4以下的使用这个方法处理照片
filePath = handleImageBeforeKitkat(data);
}
}
File file = new File(filePath);
Bitmap bitmap = compressImage(BitmapFactory.decodeFile(filePath));
String base64Bitmap = bitmapToBase64(bitmap);
this.send2JsCommonUtils(String.format("G.eventMgr.emit('CAMERA_PICK_MESSAGE_ARRIVE', '%s', '%s')", filePath, base64Bitmap));
// final String callJsFunc = String.format("PlatForm.onPickImageResult(\'%s\',\'%s\');",filePath,base64Bitmap);
// CocosHelper.runOnGameThread(new Runnable() {
// @Override
// public void run() {
// CocosJavascriptJavaBridge.evalString(callJsFunc);
// Log.i("pickImg","返回path,base64,callFuncStr = "+callJsFunc);
// }
// });
}
}
// else if(requestCode == REQUEST_CODE_CAMERA && resultCode == instance.RESULT_OK){
// Bitmap bitmap = null;
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// if(needClip == 1){
// startPhotoZoom(mCameraUri);
// return;
// }
// String filePath = changeUriToPath(mCameraUri);
// bitmap = BitmapFactory.decodeFile(filePath);
// String base64Bitmap = bitmapToBase64(bitmap);
// final String callJsFunc = String.format("PlatForm.onPickImageResult(\'%s\',\'%s\');",filePath,base64Bitmap);
// instance.runOnGLThread(new Runnable() {
// @Override
// public void run() {
// Cocos2dxJavascriptJavaBridge.evalString(callJsFunc);
// Log.i("pickImg","返回path,base64,callFuncStr = "+callJsFunc);
// }
// });
// } else {
// bitmap = BitmapFactory.decodeFile(mCameraImagePath);
// String base64Bitmap = bitmapToBase64(bitmap);
// Log.i("pickImg ","base64Image222 = "+base64Bitmap);
// final String callJsFunc = String.format("PlatForm.onPickImageResult(\'%s\',\'%s\');",mCameraImagePath,base64Bitmap);
// instance.runOnGLThread(new Runnable() {
// @Override
// public void run() {
// Cocos2dxJavascriptJavaBridge.evalString(callJsFunc);
// Log.i("pickImg","返回path,base64,callFuncStr = "+callJsFunc);
// }
// });
// }
//
// }
else if(requestCode == REQUEST_CODE_CROP && resultCode == instance.RESULT_OK){
Log.i("pickImg","裁剪完成"+data.getData());
if(data != null){
if(photoType == 1){
String filePath = null;
if (resultCode == instance.RESULT_OK) {
//判断手机的系统版本号
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//4.4系统的及以上用此方法处理照片
// filePath = handleImageOnKitkat(data);
filePath = changeUriToPath(uriClipUri);
} else {
// 4.4以下的使用这个方法处理照片
// filePath = handleImageBeforeKitkat(data);
filePath = getImagePath(uriClipUri, null);
}
}
File file = new File(filePath);
Bitmap bitmap = compressImage(BitmapFactory.decodeFile(filePath));
String base64Bitmap = bitmapToBase64(bitmap);
this.send2JsCommonUtils(String.format("G.eventMgr.emit('CAMERA_MESSAGE_ARRIVE', '%s', '%s')", filePath, base64Bitmap));
// final String callJsFunc = String.format("PlatForm.onPickImageResult(\'%s\',\'%s\');",filePath,base64Bitmap);
// CocosHelper.runOnGameThread(new Runnable() {
// @Override
// public void run() {
// CocosJavascriptJavaBridge.evalString(callJsFunc);
// Log.i("pickImg","crop返回path,base64,callFuncStr = "+callJsFunc);
// }
// });
}else if(photoType == 2){
// Bitmap bitmap = null;
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// String filePath = changeUriToPath(mCameraUri);
// bitmap = BitmapFactory.decodeFile(filePath);
// String base64Bitmap = bitmapToBase64(bitmap);
// final String callJsFunc = String.format("PlatForm.onPickImageResult(\'%s\',\'%s\');",filePath,base64Bitmap);
// CocosHelper.runOnGameThread(new Runnable() {
// @Override
// public void run() {
// Cocos2dxJavascriptJavaBridge.evalString(callJsFunc);
// Log.i("pickImg","返回path,base64,callFuncStr = "+callJsFunc);
// }
// });
// } else {
// bitmap = BitmapFactory.decodeFile(mCameraImagePath);
// String base64Bitmap = bitmapToBase64(bitmap);
// final String callJsFunc = String.format("PlatForm.onPickImageResult(\'%s\',\'%s\');",mCameraImagePath,base64Bitmap);
// CocosHelper.runOnGameThread(new Runnable() {
// @Override
// public void run() {
// Cocos2dxJavascriptJavaBridge.evalString(callJsFunc);
// Log.i("pickImg","返回path,base64,callFuncStr = "+callJsFunc);
// }
// });
// }
}
}
}
}
private Bitmap compressImage(Bitmap beforeBitmap) {
// 可以捕获内存缓冲区的数据,转换成字节数组。
ByteArrayOutputStream bos = new ByteArrayOutputStream();
if (beforeBitmap != null) {
// 第一个参数:图片压缩的格式;第二个参数:压缩的比率;第三个参数:压缩的数据存放到bos中
beforeBitmap.compress(Bitmap.CompressFormat.JPEG, 30, bos);
// 循环判断压缩后的图片大小是否满足要求,这里限制100kb,若不满足则继续压缩,每次递减10%压缩
int options = 100;
while (bos.toByteArray().length / 1024 > 100) {
bos.reset();// 置为空
beforeBitmap.compress(Bitmap.CompressFormat.JPEG, options, bos);
options -= 10;
}
// 从bos中将数据读出来 转换成图片
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
Bitmap afterBitmap = BitmapFactory.decodeStream(bis);
return afterBitmap;
}
return null;
}
private void send2JsCommonUtils(String callJsFunc) {
CocosHelper.runOnGameThread(new Runnable() {
@Override
public void run() {
CocosJavascriptJavaBridge.evalString(callJsFunc);
Log.i("pickImg","crop返回path,base64,callFuncStr = "+callJsFunc);
}
});
}
public static void onNewIntent(Intent intent) {
Log.d("RtmSdk", "=========== onNewIntent ");
}
}
java代码 AppActivity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
CommonUtils.getInstance().onActivityResult(requestCode, resultCode, data);
// SDKWrapper.shared().onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CommonUtils.getInstance().initComUtils(this);
}
js代码
const commonPath = 'com/cocos/common/CommonUtils';
//选择相册图片
public selectPhoto(clipSize: Size = new Size(150, 150), needClip = 1) {
var clipX = 0;
var clipY = 0;
if(clipSize){
clipX = clipSize.x;
clipY = clipSize.y;
}
var dict ={
needClip: needClip, //1是裁剪,2是不裁剪
clipX:clipX, //裁剪x尺寸
clipY:clipY, //裁剪y尺寸
}
let tmpPath = jsb.fileUtils.getWritablePath() + 'tmpPhoto.jpg';
if (sys.os == sys.OS.ANDROID) {
jsb.reflection.callStaticMethod(
commonPath,
"selectPhoto",
"(Ljava/lang/String;Ljava/lang/String;)V",
tmpPath,
JSON.stringify(dict));
} else if (sys.os == sys.OS.IOS) {
jsb.reflection.callStaticMethod("DeviceModule", "selectPhoto", tmpPath, JSON.stringify(dict));
} else {
let path = jsb.fileUtils.getWritablePath() + 'tmpPhoto.jpg';
// cc.director.emit("SelectPhotoCallback", path);
}
}
js回调
{
G.eventMgr.on(EventConst.CAMERA_PICK_MESSAGE_ARRIVE, this.onPickImageArrive, this);
G.eventMgr.on(EventConst.CAMERA_MESSAGE_ARRIVE, this.onImageArrive, this);
}
public onPickImageArrive(filePath: string, filedata) {
console.error(`onPickImageArrive filePath: ${filePath}`);
console.error(filedata)
}
public onImageArrive(filePath: string, filedata) {
console.error(`onImageArrive filePath: ${filePath}`);
console.error(filedata)
}
java层还需要修改: 在gradle.properrties 里添加
android.useAndroidX=true
android.enableJetifier=true
在AndoridMainfest里添加
<!-- 相册权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="包名.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
然后再res下面创建xml/file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Offer access to files under Context.getCacheDir() -->
<cache-path name="my_cache" />
<files-path name="my_files" path = "." />
<external-path name="my_external" path = "." />
<external-path path="." name="camera_photos" />
</paths>