Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is cause for this issue "Cannot convert argument of type class org.json.JSONArray" in react-native android?

I'm trying to write the plugin to get the applist with package name and icon in the react-native. I'm getting all the required data in the form of JSONArray and the images are getting stored in the sdcard.

I'm using the callback to return the result(JSON Array) back to javascript(Success or failure). I'm getting the above mentioned error.

Please find the java code which is fetching the details as below.

package com.sampleapp;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.views.drawer.ReactDrawerLayoutManager;
import com.facebook.react.views.image.ReactImageManager;
import com.facebook.react.views.progressbar.ReactProgressBarViewManager;
import com.facebook.react.views.scroll.ReactHorizontalScrollViewManager;
import com.facebook.react.views.scroll.ReactScrollViewManager;
import com.facebook.react.views.switchview.ReactSwitchManager;
import com.facebook.react.views.text.ReactRawTextManager;
import com.facebook.react.views.text.ReactTextViewManager;
import com.facebook.react.views.text.ReactVirtualTextViewManager;
import com.facebook.react.views.textinput.ReactTextInputManager;
import com.facebook.react.views.toolbar.ReactToolbarManager;
import com.facebook.react.views.view.ReactViewManager;
import com.facebook.react.views.viewpager.ReactViewPagerManager;

public class ToastModule extends ReactContextBaseJavaModule {
    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";
    public static JSONArray applist;

    public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "ToastAnd";
    }

    @ReactMethod
    public void show(Callback errorCallback, Callback successCallback) {
        try {
            //get a list of installed apps.
            PackageManager pm = getReactApplicationContext().getPackageManager();
            List<ApplicationInfo> packages = pm.getInstalledApplications(0);

            JSONArray app_list = new JSONArray();
            int cnt = 0;
            String path = getSDPath();
            makeRootDirectory(path + "/com.framework.xxx/");
            makeRootDirectory(path + "/com.framework.xxx/Cache/");
            for (ApplicationInfo packageInfo : packages) {
                try {

                    if (getReactApplicationContext().getPackageManager().getLaunchIntentForPackage(packageInfo.packageName) != null) {
                        JSONObject info = new JSONObject();
                        info.put("name", packageInfo.loadLabel(pm));
                        info.put("packagename", packageInfo.packageName);
                        String img_name = "/com.ionicframework.xxx/Cache/" + packageInfo.packageName + ".png";
                        info.put("img", path + img_name);
                        //cheak exist  or not
                        File cheakfile = new File(path + img_name);
                        if (!cheakfile.exists()) {

                            Drawable icon = pm.getApplicationIcon(packageInfo);
                            if (icon != null) {
                                drawableTofile(icon, path + img_name);
                            }
                        }
                        app_list.put(cnt++, info);
                    }
                } catch (Exception ex) {
                    System.err.println("Exception: " + ex.getMessage());
                }
            }
            applist = app_list;
            successCallback.invoke(applist);

        } catch (Exception e) {
            errorCallback.invoke(e.getMessage());
        }
    }

    public static void drawableTofile(Drawable drawable,String path)
    {
        File file = new File(path);
        Bitmap bitmap=((BitmapDrawable)drawable).getBitmap();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100 /*ignored for PNG*/, bos);
        byte[] bitmapdata = bos.toByteArray();


        //write the bytes in file
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(file);
            fos.write(bitmapdata);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public String getSDPath()
    {
        File SDdir = null;
        boolean sdCardExist= Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
        if(sdCardExist){
            SDdir=Environment.getExternalStorageDirectory();
        }
        if(SDdir!=null){

            return SDdir.toString();
        }
        else{
            return null;
        }
    }

    public static void makeRootDirectory(String filePath) {
        File file = null;
        try {
            file = new File(filePath);
            if (!file.exists()) {
                file.mkdirs();  //make Directory
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

In the android.index.js i'm calling the native method as shown below:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict';

var React = require('react-native');

var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
} = React;

var toastMessage = require('./sampleToast');
toastMessage.show(
  (msg) => { console.log(msg); },
   (result) => { alert(JSON.stringify(result)); }

  );

var SampleApp = React.createClass({
  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.android.js
        </Text>
        <Text style={styles.instructions}>
          Shake or press menu button for dev menu
        </Text>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('SampleApp', () => SampleApp);

But the in the java code while return the applist(successCallback.invoke(applist);) i'm getting the above mentioned error.

could you help me where i'm doing wrong. Thanks

Detailed Error:

Exception in native call from JS
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React: java.lang.RuntimeException: Cannot convert argument of type class org.json.JSONArray
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.Arguments.fromJavaArgs(Arguments.java:55)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.CallbackImpl.invoke(CallbackImpl.java:27)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.sampleapp.ToastModule.show(ToastModule.java:100)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at java.lang.reflect.Method.invokeNative(Native Method)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at java.lang.reflect.Method.invoke(Method.java:515)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.BaseJavaModule$JavaMethod.invoke(BaseJavaModule.java:106)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.NativeModuleRegistry$ModuleDefinition.call(NativeModuleRegistry.java:143)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.NativeModuleRegistry.call(NativeModuleRegistry.java:64)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.CatalystInstance$NativeModulesReactCallback.call(CatalystInstance.java:366)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at android.os.Handler.handleCallback(Handler.java:733)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at android.os.Handler.dispatchMessage(Handler.java:95)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at android.os.Looper.loop(Looper.java:136)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at com.facebook.react.bridge.queue.MessageQueueThread$1.run(MessageQueueThread.java:137)
11-14 09:01:24.780 20592-20624/com.sampleapp E/unknown:React:     at java.lang.Thread.run(Thread.java:841)
like image 706
coders Avatar asked Nov 14 '15 13:11

coders


1 Answers

When working Native bridges, callbacks should be invoked with WritableNative components from the com.facebook.react.bridge package.

Instead of a JSONObject, use a WritableNativeMap.
Instead of a JSONArray, use a WritableNativeArray.

For instance, with a WritableNativeMap:

@ReactMethod
public void reactMethod(Callback onSuccess) {
  WritableMap resultData = new WritableNativeMap();
  resultData.putString("key1", "data");
  resultData.putString("key2", "data2");

  onSuccessCallback(resultData);
}

In your case, you should have something like:

public static WritableArray applist;

// ...

@ReactMethod
public void show(Callback errorCallback, Callback successCallback) {
    try {
        //get a list of installed apps.
        PackageManager pm = getReactApplicationContext().getPackageManager();
        List<ApplicationInfo> packages = pm.getInstalledApplications(0);

        WritableArray app_list = new WritableNativeArray();

        // ...

        for (ApplicationInfo packageInfo : packages) {
            try {

                if (getReactApplicationContext().getPackageManager().getLaunchIntentForPackage(packageInfo.packageName) != null) {
                    WritableMap info = new WritableNativeMap();
                    info.putString("name", packageInfo.loadLabel(pm).toString());
                    info.putString("packagename", packageInfo.packageName);

                    // ...

                    app_list.pushMap(info);
                }
            } catch (Exception ex) {
                System.err.println("Exception: " + ex.getMessage());
            }
        }
        applist = app_list;
        successCallback.invoke(applist);

    } catch (Exception e) {
        errorCallback.invoke(e.getMessage());
    }
}
like image 171
Almouro Avatar answered Oct 02 '22 23:10

Almouro