The source code has been uploaded to Github: https://github.com/songxiaoliang/native-read-rn-image
In ReactNative the development process, and sometimes need to display RN in the picture in the original Shengduan, so that the benefits can be hot update to update the APP in the picture, without the need to release a native version, but ReactNative in the picture path is relative, similar to './xxximage.png'
the In writing, the native end cannot resolve such paths, so what if the RN's picture is passed to the native end?
solution
1. If the picture uses a network picture, it only needs to pass the url string address to the native. This method requires time and the network environment to load the picture. It is not a local picture and is not the best way for this solution.
2. The lazy approach is to generate a base64 string from the RN's local picture and pass it to the native for parsing. If the picture is too large, the string will be quite long, which is also not considered the best solution.
In fact, RN provides related solutions, as follows:
resolveAssetSource()
Image.resolveAssetSource(source);
Resolves an asset reference into an object which has the properties uri
, width
, and height
.
Parameters:
NAME | TYPE | REQUIRED | DESCRIPTION |
---|---|---|---|
source | number, object | Yes | A number (opaque type returned by require('./foo.png')) or an ImageSource . |
ImageSource
is an object like{ uri: '<http location || file path>' }
resolveAssetSource 方法可以将资产引用解析为具有uri,width和height属性的对象。参数为一个数字(由require('。/ foo.png')返回的opaque类型)或 ImageSource。
The sample code is as follows:
const myImage = require('./Images/icon_splash.jpg');
const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
const resolvedImage = resolveAssetSource(myImage);
console.log(resolvedImage);
The print result of resolveImage is as follows:
can be seen,resolveAssetSource 方法不仅返回了图片到宽高,还有Uri及scale属性值。
上图中,Uri的值为 http:// 开头的链接,这就涉及到RN对于Uri的定义规则:
(1)开发者模式下,图片会由Package Server 本地服务器加载,Uri会返http的本地链接。
(2)发布模式下,图片已经被打包到原生目录下,例如Android端res下的drawable资源目录
。
So we can get the picture resources defined in rn through Uri on the native side.
Android side
/**
* release模式下 uri为图片名称,例如, 在rn项目的Images目录下有张icon_splash名称的图片
* 那么 uri 为 images_icon_splash
* 开发者模式下,图片格式为package server 地址,例如: http: // 192.xxx
* @param params
*/
@ReactMethod
public void showRNImage(ReadableMap params) {
String rnImageUri;
try {
rnImageUri = params.getString("uri");
Log.i("showRNImage", "uri : " + rnImageUri);
BitmapUtil.loadImage(rnImageUri);
} catch (Exception e) {
return;
}
}
The loadImage method receives Uri parameters. Look at how the loadImage method is implemented:
public static Drawable loadImage(String iconUri) {
if (TextUtils.isEmpty(iconUri)) {
return null;
}
Log.e("BitmapUtil", "isDebug: " + MainApplication.instance.isDebug());
if (MainApplication.instance.isDebug()) {
return JsDevImageLoader.loadIcon(iconUri);
} else {
Uri uri = Uri.parse(iconUri);
if (isLocalFile(uri)) {
// 本地文件
return loadFile(uri);
} else {
return loadResource(iconUri);
}
}
}
First of all, we judge whether it is the developer mode, if it is, then execute the loadIcon method to load directly from the local directory. Otherwise, load from the local directory of the mobile phone or according to the resource ID.
In development mode, Uri is in link mode, so we can get it by streaming
@NonNull
private static Drawable tryLoadIcon(String iconDevUri) throws IOException {
URL url = new URL(iconDevUri);
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
BitmapDrawable bitmapDrawable = new BitmapDrawable(MainApplication.instance.getResources(), bitmap);
Log.e("JsDevImageLoader", "bitmap drawable width:" + bitmapDrawable.getIntrinsicWidth());
return bitmapDrawable;
}
The release mode is as follows:
/**
* 加载手机本地目录图片
* @param uri
* @return
*/
private static Drawable loadFile(Uri uri) {
Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
return new BitmapDrawable(MainApplication.instance.getResources(), bitmap);
}
/**
* 加载drawable目录下的图片
* @param iconUri
* @return
*/
private static Drawable loadResource(String iconUri) {
return ResourceDrawableIdHelper
.instance
.getResourceDrawable(MainApplication.instance, iconUri);
}
iOS edge
The iOS side is much simpler than Android, and only needs to be directly parsed into a UIImage:
#import <React/RCTConvert.h>
RCT_EXPORT_METHOD(showRNImage:(id)rnImageData){
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *rnImage = [RCTConvert UIImage:rnImageData];
...
});
}
to sum up
Reading the RN picture on the native side, whether it is hybrid development or pure RN development, involves many usage scenarios. For example, dynamically update Splash. So mastering this skill will help us make better applications.