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)
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());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With