The solution

1. If the picture uses the network graph, it only needs to transfer the URL string address to the native. This method needs time and network environment to load the picture, which does not belong to the local picture and is not the best way pursued by this scheme.

The lazy approach is to generate a Base64 string from a local image of RN and pass it to the native for parsing. If the image is too large, the string will be quite long, which is also not considered the best solution.

RN provides relevant solutions as follows:

resolveAssetSource()

Image.resolveAssetSource(source);Copy the code

Resolves an asset reference into an object which has the properties uri, width, and height.

The resolveAssetSource method resolves an asset reference to an object with uri, width, and height attributes. The argument is a number (specified by require (‘. / foo.png’) returns opaque type) or ImageSource.

Example 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);Copy the code

The print result of resolveImage is as follows:



As you can see, the resolveAssetSource method not only returns the image to the width and height, but also to the Uri and scale properties. In the figure above, the Uri is a link starting with http://, which refers to RN’s rules for defining URIs:

(1) In developer mode, images will be loaded by the Package Server local Server, and the Uri will return the HTTP local link.

(2) In publish mode, images have been packed into a native directory, such as the Drawable resource directory under RES on Android. So we can get image resources defined in RN by Uri on the native end.

The Android end

/** * In release mode, the uri is the image name. For example, if there is an image named icon_splash in the Images directory of the RN project, then the URI is images_icon_splash. The image format is package Server address, for example: 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; }}Copy the code

The loadImage method receives Uri arguments. See 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)) {
                // Local file
                return loadFile(uri);
            } else {
                returnloadResource(iconUri); }}}Copy the code

The loadImage method receives Uri arguments. See 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)) {
                // Local file
                return loadFile(uri);
            } else {
                returnloadResource(iconUri); }}}Copy the code

First we check if it is developer mode, if it is loadIcon and load directly from the local directory. Otherwise, the load is performed from the local directory of the mobile phone or based on the resource ID.

In development mode, urIs are in linked mode, so we can fetch them through streams

    @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;
    }Copy the code

There are two release modes:

    /** * Load the phone local directory image *@param uri
     * @return* /
    private static Drawable loadFile(Uri uri) {
        Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
        return new BitmapDrawable(MainApplication.instance.getResources(), bitmap);
    }
 
    Drawable (drawable); /** *@param iconUri
     * @return* /
    private static Drawable loadResource(String iconUri) {
        return ResourceDrawableIdHelper
                .instance
                .getResourceDrawable(MainApplication.instance, iconUri);
    }Copy the code

The iOS side

IOS is much simpler than Android, just need to directly parse into UIImage:

#import <React/RCTConvert.h>
 
RCT_EXPORT_METHOD(showRNImage:(id)rnImageData){
    dispatch_async(dispatch_get_main_queue(), ^{
    UIImage *rnImage = [RCTConvert UIImage:rnImageData]; . }); }Copy the code

conclusion

Reading RN images on the native side, whether in hybrid or pure RN development, involves a number of scenarios. For example, dynamically update Splash. So having this skill helps us make better applications.