Cordova Android自定义插件/应用程序 - 自定义插件上找不到类别

时间:2017-08-04 16:06:20

标签: android cordova plugins cordova-plugins classnotfoundexception

我正在为Cordova设计一个自定义插件作为教育演示。该插件与Android PdfRenderer类集成,并将API暴露给Cordova生态系统。

我的自定义插件正在编译而没有错误,我已将插件添加到我的测试项目中。但是,当我构建并运行测试项目时,应用程序在启动时崩溃,并且我遇到以下消息:

java.lang.ClassNotFoundException: com.dev.plugin.PdfRendererPlugin

我已经检查了我的platforms/android/文件夹,并且按照预期在src/com/dev/plugin/PdfRenderPlugin.java找到了插件类。

在这种情况下我还应该寻找什么呢?看起来我的应用程序现在应该正常工作,如果插件编译并添加到项目中没有错误。

以下是一些可以使用的代码:

的plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
    id="cordova-android-pdf-renderer-plugin" version="0.2.3">
<name>PdfRendererPlugin</name>
<description>Cordova PDF Renderer Plugin</description>
<license>MIT</license>
<keywords>cordova,pdf,renderer</keywords>

<platform name="android">
    <js-module src="www/js/PdfRendererPlugin.js" name="PdfRendererPlugin">
        <runs/>

        <clobbers target="PdfRendererPlugin" />
    </js-module>

    <config-file target="config.xml" parent="/*">
        <feature name="com.dev.plugin.PdfRendererPlugin">
            <param name="android-package" value="com.dev.plugin.PdfRendererPlugin"/>
            <param name="onload" value="true" />
        </feature>
    </config-file>

    <source-file src="src/android/PdfRendererPlugin.java" target-dir="src/com/dev/plugin/" />
</platform>
</plugin>

插件类(PdfRendererService)

package com.dev.plugin.PdfRendererService;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.PluginResult;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import android.content.pm.PackageManager;

import android.graphics.Bitmap;
import android.graphics.pdf.PdfRenderer;
import android.graphics.pdf.PdfRenderer.Page;

import android.os.ParcelFileDescriptor;

import android.util.Log;

/**
 * This class handles a pdf file called from JavaScript and converts a selected 
page (default is first) to a byte array representing a bitmap.
 */
public class PdfRendererPlugin extends CordovaPlugin {

private static final String LOG_TAG = "PdfRendererPlugin";

private ParcelFileDescriptor fileDescriptor = null;
private PdfRenderer renderer = null;
private Page currentPage = null;

private int mWidth = 400, mHeight = 600;
private String mRenderMode = "display";

@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView){
    Log.d(LOG_TAG, "initialize");
    super.initialize(cordova, webView);
}

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    Log.d(LOG_TAG, "execute");

    //No Switch -> src 1.6
    if(action.equals("open")){
        return executeOpen(args, callbackContext);
    }
    else if(action.equals("renderPage")){
        return executeRenderPage(args, callbackContext);
    }
    else if(action.equals("pageCount")){
        callbackContext.success(this.getPageCount());
        return true;
    }
    else if(action.equals("close")){
        this.closeRenderer();
        callbackContext.success();
        return true;
    }

    return false;
}

private boolean executeOpen(JSONArray args, CallbackContext callbackContext){
    Log.d(LOG_TAG, "executeOpen");
    String filePath = "";
    try{
        if(args.length() < 1){
            Log.e(LOG_TAG, "No arguments provided. Exiting process.");
            callbackContext.error("No arguments provided. Exiting process.");
            return true;
        }
        else if(args.length() < 2){
            Log.e(LOG_TAG, "Insufficient arguments provided. Exiting process.");
            callbackContext.error("Insufficient arguments provided. Exiting process.");
            return true;
        }
        if(args.length() > 3){
            mWidth = args.getInt(2);
            mHeight = args.getInt(3);
        }

        filePath = args.getString(0);
        mRenderMode = args.getString(1);
    }
    catch(JSONException je){
        String msg = je.getMessage();
        if(msg == null)
            msg = "Unknown JSONException has occurred";
        Log.e(LOG_TAG, msg);
    }

    this.initializeRenderer(filePath, callbackContext);

    boolean isPageOpen = this.openPage(0, callbackContext);
    if(isPageOpen){
        Bitmap bitmap = getBitmap(mWidth, mHeight);
        this.sendBitmapAsBytes(0, bitmap, callbackContext);
    }
    return true;
}

private boolean executeRenderPage(JSONArray args, CallbackContext callbackContext){
    Log.d(LOG_TAG, "executeRenderPage");
    int pageNo = -1;
    try {
        if (args.length() < 1) {
            Log.e(LOG_TAG, "No arguments provided. Exiting process.");
            callbackContext.error("No arguments provided. Exiting process.");
            return true;
        }
        if (args.length() > 1) {
            mRenderMode = args.getString(1);
        }
        if (args.length() > 3) {
            mWidth = args.getInt(2);
            mHeight = args.getInt(3);
        }

        pageNo = args.getInt(0);
    }
    catch(JSONException je){
        String msg = je.getMessage();
        if(msg == null)
            msg = "Unknown JSONException has occurred";
        Log.e(LOG_TAG, msg);
    }

    if(pageNo < 0)
        return false;

    boolean isPageOpen = this.openPage(pageNo, callbackContext);
    if(isPageOpen) {
        Bitmap bitmap = getBitmap(mWidth, mHeight);
        this.sendBitmapAsBytes(pageNo, bitmap, callbackContext);
    }
    return true;
}

/*
// Requests the permission to read from external storage if not already available
private void validatePermissions(){
    Log.d(LOG_TAG, "validatePermissions");
    if(!cordova.hasPermission(READ_EXTERNAL_STORAGE)){
        Log.i(LOG_TAG, "Requesting External Storage Read Permission...");
        cordova.requestPermission(this, CODE_READ_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE);
    }
}
*/

private int getPageCount() {
    Log.d(LOG_TAG, "getPageCount");
    if(renderer == null)
        return 0;

    return renderer.getPageCount();
}

private void initializeWriteFileDescriptor(String filePath, CallbackContext callbackContext) throws FileNotFoundException, FileFormatException {
    Log.d(LOG_TAG, "initializeWriteFileDescriptor");
    fileDescriptor = null;

    if(filePath == null || filePath.length() < 1)
        throw new FileNotFoundException("The file path provided is not a valid file path.");

    String[] pathArr = filePath.split(".");
    int numSections = pathArr.length;
    String ext = pathArr[numSections - 1];

    if(!ext.equals("pdf"))
        throw new FileFormatException("Invalid File Extension provided to Pdf Render Service: " + ext);

    fileDescriptor = getWriteFileDescriptor(filePath);
}

private void initializeRenderer(String filePath, CallbackContext callbackContext){
    Log.d(LOG_TAG, "initializeRenderer");
    renderer = null;

    try {
        initializeWriteFileDescriptor(filePath, callbackContext);

        renderer = new PdfRenderer(fileDescriptor);
    }
    catch(IOException io){
        String msg = io.getMessage();
        if(msg == null)
            msg = "An error has occurred while loading the requested file.";

        Log.e(LOG_TAG, msg);
        callbackContext.error(msg);
    }
}

private void closeRenderer() {
    Log.d(LOG_TAG, "closeRenderer");
    if(renderer == null) {
        Log.w(LOG_TAG, "Attempted to close null renderer. Skipping operation.");
        return;
    }

    renderer.close();
}

private boolean openPage(int index, CallbackContext callbackContext){
    Log.d(LOG_TAG, "openPage");
    currentPage = null;

    int pageCount = getPageCount();
    if(pageCount < 1) {
        Log.e(LOG_TAG, "Requested document has no pages to display.");
        callbackContext.error("Requested document has no pages to display.");
        return false;
    }

    if(index >= pageCount || index < 0) {
        Log.e(LOG_TAG, String.format("No page was found at page number %d/%d", index, pageCount));
        callbackContext.error(String.format("No page was found at page number %d/%d", index, pageCount));
        return false;
    }

    currentPage = renderer.openPage(index);
    return true;
}

private void sendBitmapAsBytes(int index, Bitmap bitmap, CallbackContext callbackContext){
    Log.d(LOG_TAG, "sendBitmapAsBytes");
    if(renderer == null) {
        Log.e(LOG_TAG, "Renderer was not properly initialized.");
        callbackContext.error("Renderer was not properly initialized.");
        return;
    }

    if(currentPage == null) {
        Log.e(LOG_TAG, "Requested page could not be rendered.");
        callbackContext.error("Requested page could not be rendered.");
        return;
    }

    int renderMode = mRenderMode.equals("print") ? Page.RENDER_MODE_FOR_PRINT : Page.RENDER_MODE_FOR_DISPLAY;
    currentPage.render(bitmap, null, null, renderMode);

    byte[] output = toByteArray(bitmap);
    if(output == null || output.length < 1) {
        Log.e(LOG_TAG, "Bitmap Error has occurred: Invalid Output Format Detected");
        callbackContext.error("Bitmap Error has occurred: Invalid Output Format Detected");
    }
    else {
        Log.i(LOG_TAG, "Bitmap Conversion Successful");
        callbackContext.success(output);
    }
}

private static byte[] toByteArray(Bitmap bitmap){
    Log.d(LOG_TAG, "toByteArray");
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);

    return stream.toByteArray();
}

private static Bitmap getBitmap(int width, int height){
    Log.d(LOG_TAG, "getBitmap");
    return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}

private static ParcelFileDescriptor getWriteFileDescriptor(String filePath) throws FileNotFoundException {
    Log.d(LOG_TAG, "getWriteFileDescriptor");
    File file = new File(filePath);
    final int fileMode = ParcelFileDescriptor.MODE_TRUNCATE |
                         ParcelFileDescriptor.MODE_CREATE   |
                         ParcelFileDescriptor.MODE_WRITE_ONLY;

    return ParcelFileDescriptor.open(file, fileMode);
}

class FileFormatException extends IOException {
    FileFormatException(String msg){
        super(msg);
    }
}
}

插件JS接口

var PLUGIN_NAME = "PdfRendererPlugin";

var SERVICE_OPEN = "open";
var SERVICE_CLOSE = "close";
var SERVICE_PAGE_COUNT = "pageCount";
var SERVICE_RENDER_PAGE = "renderPage";

var RENDER_MODE_DISPLAY = "display";
var RENDER_MODE_PRINT = "print";

var PdfRendererPlugin = {
display: function(filePath, callback){
    cordova.exec(callback, function(err){
        // console.log(err);
    }, PLUGIN_NAME, SERVICE_OPEN, [filePath, RENDER_MODE_DISPLAY]);
},

displayWithDimensions: function(filePath, width, height, callback){
    cordova.exec(callback, function(err){
        // console.log(err);
    }, PLUGIN_NAME, SERVICE_OPEN, [filePath, RENDER_MODE_DISPLAY, width, height]);
},

print: function(filePath, callback){
    cordova.exec(callback, function(err){
       // console.log(err);
    }, PLUGIN_NAME, SERVICE_OPEN, [filePath, RENDER_MODE_PRINT]);
},

printWithDimensions: function(filePath, width, height, callback){
    cordova.exec(callback, function(err){
       // console.log(err);
    }, PLUGIN_NAME, SERVICE_OPEN, [filePath, RENDER_MODE_PRINT, width, height]);
},

renderPage: function(pageNo, callback){
    cordova.exec(callback, function(err){
        //console.log(err);
    }, PLUGIN_NAME, SERVICE_RENDER_PAGE, [pageNo]);
},

renderPageForDisplay: function(pageNo, callback){
    cordova.exec(callback, function(err){
       // console.log(err);
    }, PLUGIN_NAME, SERVICE_RENDER_PAGE, [pageNo, RENDER_MODE_DISPLAY]);
},

renderPageForDisplayWithDimensions: function(pageNo, width, height, callback){
    cordova.exec(callback, function(err){
       // console.log(err);
    }, PLUGIN_NAME, SERVICE_RENDER_PAGE, [pageNo, RENDER_MODE_DISPLAY, width, height]);
},

renderPageForPrint: function(pageNo, callback){
    cordova.exec(callback, function(err){
       // console.log(err);
    }, PLUGIN_NAME, SERVICE_RENDER_PAGE, [pageNo, RENDER_MODE_PRINT]);
},

renderPageForPrintWithDimensions: function(pageNo, width, height, callback){
    cordova.exec(callback, function(err){
        //console.log(err);
    }, PLUGIN_NAME, SERVICE_RENDER_PAGE, [pageNo, RENDER_MODE_PRINT, width, height]);
},

close: function(callback){
    cordova.exec(callback, function(err){
      //  console.log(err);
    }, PLUGIN_NAME, SERVICE_CLOSE, []);
},

getPageCount: function(callback){
    cordova.exec(callback, function(err){
       // console.log(err);
    }, PLUGIN_NAME, SERVICE_PAGE_COUNT, []);
}
};

测试应用程序index.html

<!DOCTYPE html>
<html>
<head>
    <title>Cordova PDF Generator Plugin Test</title>

    <meta name="viewport" content="user-scalable=no, initial-scale=1,
          maximum-scale=1, minimum-scale=1, width=device-width,
          height=device-height" />
</head>
<body>
    <div class="app">
        <h1>Cordova PDF Generation Plugin Test</h1>

        <div>
            <button id="display-button" onclick="display()">Display (View)</button>
            <button id="print-button" onclick="print()">Display (Print)</button>
        </div>
    </div>

    <script type="text/javascript" src="cordova.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
</body>
</html>

测试应用程序index.js

var testFilePath = 'assets/test-file.pdf';

var app = {
// Application Constructor
initialize: function() {
    document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},

// deviceready Event Handler
//
// Bind any cordova events here. Common events are:
// 'pause', 'resume', etc.
onDeviceReady: function() {
    display();
}
};

var display = function(){
PdfRendererPlugin.display(testFilePath, function(data){
        console.log('Bitmap Bytes');
        console.log(data);
    });
};

var print = function(){
PdfRendererPlugin.print(testFilePath, function(data){
        console.log('Bitmap Bytes');
        console.log(data);
    });
};

app.initialize();

1 个答案:

答案 0 :(得分:0)

我觉得很傻。问题出在包装声明上。我在没有考虑它的情况下将类名添加到包声明中(这一定是因为我从plugin.xml中复制并粘贴了包含类名的路径)。