首先要特别提醒的地方就是版本问题,我就是因为版本问题,刚开始搞得我的项目一直报错。。。
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
android.os.FileUriExposedException: file:///storage/emulated/0/IDCardSDKCaller/card.jpg exposed beyond app through ClipData.Item.getUri()
主要就是因为版本问题,刚开始百度的时候,告诉我说是因为权限问题,让我添加权限,后来多次尝试无果,后来才知道,这因为版本6.0前后的问题,首先看个比较简单的就是选择本地图片,这个没什么问题
/*选图*/
@ReactMethod
public void RNCallSelectedPhotoAction(Callback callback) {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
intent.setType("image/*");// 相片类型
getCurrentActivity().startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
this.callback = callback;
}
这个选择图片去网上搜索,一大把,都是通用的,当然也没什么问题,最主要的问题就是拍照,因为权限问题,所以肯定就是要进行判断了
/*拍照*/
@ReactMethod
private void RNCallStartCapture(Callback callback) {
this.callback = callback;
if (mTakePicPath == null) {
mTakePicPath = DIR_ICR + "/" + System.currentTimeMillis() + ".jpg";
}
File dir = new File(mTakePicPath);
if (!dir.exists()) {
try {
dir.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(MyContext,BuildConfig.APPLICATION_ID + ".provider",dir);
}else {
uri = Uri.fromFile(dir);
}
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
getCurrentActivity().startActivityForResult(openCameraIntent, REQUEST_CAPTURE_PIC);
}
这个方法就是给rn发送数据当然要注意上下文环境
/**
* Native调用RN
* 给rn发送数据
* @param msg
*/
public void nativeCallRn(String msg) {
MyContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("nativeCallRn", msg);
callback.invoke(msg);
}
拍照和选择图片呢我主要是利用onActivityResult 来获取数据结果的
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
// 选择图片
if(null!=data){
String imgPath = getPathFromUri(getCurrentActivity(), data.getData());
imagePathCompression(imgPath);
}
}else if (requestCode == REQUEST_CAPTURE_PIC) {
String photoPath;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
photoPath = String.valueOf(mTakePicPath);
} else {
photoPath = uri.getEncodedPath();
}
imagePathCompression(photoPath);
}
这个就是拍照和选择图片获取到的数据,当然要注意权限的判断,获取的结果也是不一样的,
imagePathCompression 这个方法是我自己根据鲁班压缩自己写的一个简单方法,(说到鲁班,强烈建议使用,一款仿微信压缩的,个人觉得写的特别好)
public void imagePathCompression(String imagePath) {
File file = new File(imagePath);
if(file.length()>1024*500){
Log.e("zeng","压缩"+imagePath);
Luban.with(MyContext)
.load(imagePath)
.ignoreBy(100)
.filter(new CompressionPredicate() {
@Override
public boolean apply(String path) {
return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif"));
}
})
.setCompressListener(new OnCompressListener() {
@Override
public void onStart() {
// TODO 压缩开始前调用,可以在方法内启动 loading UI
}
@Override
public void onSuccess(File file) {
// TODO 压缩成功后调用,返回压缩后的图片文件
String s1 = fileToBase64(file);
nativeCallRn(s1);
}
@Override
public void onError(Throwable e) {
// TODO 当压缩过程出现问题时调用
}
}).launch();
}else {
String s = imageToBase64(imagePath);
Log.e("zeng","不压缩"+s);
nativeCallRn(s);
}
}
这样的话一个简单的拍照,选择图片就做好了,当然还有转化base64压缩
RNCallAndroidAction.compressImage( ( msg) => { })
这个是rn里面写的监听方法
这个是跳转到安装页面的权限判断
private void installAPk(File apkFile) {
Log.d("zengapkFile", "upgrade: 进来了"+apkFile);
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本
Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID + ".provider", apkFile); //与manifest中定义的provider中的authorities="com.shawpoo.app.fileprovider"保持一致
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
startActivity(intent);
}