- 如何在原生端( iOS 和 android 两个平台)使用 ReactNative 里的本地图片(路径类似 require('./xxximage.png'))。
在 ReactNative 开发过程中,有时需要在原生端显示 RN 里的图片,这样的好处是可以通过热更新来更新 APP 里的图片,而不需要发布原生版本,而 ReactNative 里图片路径是相对路径,类似'./xxximage.png'的写法,原生端是无法解析这类路径,那么如果将 RN 的图片传递给原生端呢?
解决方案:
1、图片如果用网络图,那只需要将 url 字符串地址传递给原生即可,这种做法需要时间和网络环境加载图片,不属于本地图片,不是本方案所追求的最佳方式。
2、懒人做法是把 RN 的本地图片生成 base64 字符串然后传递给原生再解析,这种做法如果图片太大,字符串会相当长,同样不认为是最佳方案。
其实 RN 提供了相关的解决方法,如下:
RN 端
const myImage = require('./my-image.png');
const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
const resolvedImage = resolveAssetSource(myImage);
NativeModules.NativeBridge.showRNImage(resolvedImage);
iOS 端
#import <React/RCTConvert.h>
RCT_EXPORT_METHOD(showRNImage:(id)rnImageData){
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *rnImage = [RCTConvert UIImage:rnImageData];
...
});
}
安卓端
第一步,从桥接文件获取到 uri 地址
@
ReactMethodpublic static void showRNImage(Activity activity, ReadableMap params){
String rnImageUri;
try {
//图片地址
rnImageUri = params.getString("uri");
Log.i("Jumping", "uri : " + uri);
...
} catch (Exception e) {
return;
}
}
第二步,创建 JsDevImageLoader.java
package
com.XXX;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.StrictMode;
import android.support.annotation.NonNull;
import android.util.Log;
import com.XXX.NavigationApplication;
import java.io.IOException;
import java.net.URL;
public class JsDevImageLoader {
private static final String TAG = "JsDevImageLoader";
public static Drawable loadIcon(String iconDevUri) {
try {
StrictMode.ThreadPolicy threadPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitNetwork().build());
Drawable drawable = tryLoadIcon(iconDevUri);
StrictMode.setThreadPolicy(threadPolicy);
return drawable;
} catch (Exception e) {
Log.e(TAG, "Unable to load icon: " + iconDevUri);
return new BitmapDrawable();
}
}
@
NonNull private static Drawable tryLoadIcon(String iconDevUri) throws IOException {
URL url = new URL(iconDevUri);
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
return new BitmapDrawable(NavigationApplication.instance.getResources(), bitmap);
}
}
第三步,导入 ResourceDrawableIdHelper.java
package com.xg.navigation.react;// Copyright 2004-present Facebook. All Rights Reserved.
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import com.facebook.common.util.UriUtil;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Direct copy paste from react-native, because they made that class package scope. -_-"
* Can be deleted in react-native ^0.29
*/
public class ResourceDrawableIdHelper {
public static final ResourceDrawableIdHelper instance = new ResourceDrawableIdHelper();
private Map<String, Integer> mResourceDrawableIdMap;
public ResourceDrawableIdHelper() {
mResourceDrawableIdMap = new HashMap<>();
}
public int getResourceDrawableId(Context context, @
Nullable String name) {
if (name == null || name.isEmpty()) {
return 0;
}
name = name.toLowerCase().replace("-", "_");
if (mResourceDrawableIdMap.containsKey(name)) {
return mResourceDrawableIdMap.get(name);
}
int id = context.getResources().getIdentifier(
name,
"drawable",
context.getPackageName());
mResourceDrawableIdMap.put(name, id);
return id;
}
@
Nullable public Drawable getResourceDrawable(Context context, @
Nullable String name) {
int resId = getResourceDrawableId(context, name);
return resId > 0 ? context.getResources().getDrawable(resId) : null;
}
public Uri getResourceDrawableUri(Context context, @
Nullable String name) {
int resId = getResourceDrawableId(context, name);
return resId > 0 ? new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
.path(String.valueOf(resId))
.build() : Uri.EMPTY;
}
}
第四步,创建 BitmapUtil.java
package
com.XXX;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import com.XXX.NavigationApplication;
import com.XXX.JsDevImageLoader;
import com.XXX.ResourceDrawableIdHelper;
import java.io.IOException;
public class BitmapUtil {
private static final String FILE_SCHEME = "file";
public static Drawable loadImage(String iconSource) {
if (TextUtils.isEmpty(iconSource)) {
return null;
}
if (NavigationApplication.instance.isDebug()) {
return JsDevImageLoader.loadIcon(iconSource);
} else {
Uri uri = Uri.parse(iconSource);
if (isLocalFile(uri)) {
return loadFile(uri);
} else {
return loadResource(iconSource);
}
}
}
private static boolean isLocalFile(Uri uri) {
return FILE_SCHEME.equals(uri.getScheme());
}
private static Drawable loadFile(Uri uri) {
Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
return new BitmapDrawable(NavigationApplication.instance.getResources(), bitmap);
}
private static Drawable loadResource(String iconSource) {
return ResourceDrawableIdHelper.instance.getResourceDrawable(NavigationApplication.instance, iconSource);
}
public static Bitmap getBitmap(Activity activity, String uri) {
if (activity == null || uri == null || TextUtils.isEmpty(uri)) {
return null;
}
Uri mImageCaptureUri;
try {
mImageCaptureUri = Uri.parse(uri);
} catch (Exception e) {
e.printStackTrace();
return null;
}
if (mImageCaptureUri == null) {
return null;
}
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), mImageCaptureUri);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return bitmap;
}
}
第五步,使用第一步里的 rnImageUri 地址
...
BitmapUtil.loadImage(rnImageUri)
...
第六步,显示图片
import android.widget.RelativeLayout;
import android.support.v7.widget.AppCompatImageView;
import android.graphics.drawable.Drawable;
...
final RelativeLayout item = (RelativeLayout) mBottomBar.getChildAt(i);
final AppCompatImageView itemIcon = (AppCompatImageView) item.getChildAt(0);
itemIcon.setImageDrawable(BitmapUtil.loadImage(rnImageUri));
...