Ошибка NativeScript: java.lang.NoClassDefFoundError - PullRequest
0 голосов
/ 13 марта 2019

Я превратил приложение для Android (нативная Java) в библиотеку с файлом .aar. Я помещаю его внутрь App_Resources/android/libs и пытаюсь получить доступ к классу, но получаю эту ошибку:

JS: ОШИБКА Ошибка: Uncaught (в обещании): Ошибка: java.lang.NoClassDefFoundError: Ошибка разрешения: Lcom / github / pires / obd / reader / io / AbstractGatewayService; com.tns.Runtime.callJSMethodNative (родной метод) com.tns.Runtime.dispatchCallJSMethodNative (Runtime.java:1203) com.tns.Runtime.callJSMethodImpl (Runtime.java:1083) com.tns.Jtimetime : 1070) com.tns.Runtime.callJSMethod (Runtime.java:1050) com.tns.Runtime.callJSMethod (Runtime.java:1042) com.tns.gen.java.lang.Runnable.run (Runnable.java:15 ) android.os.Handler.handleCallback (Handler.java:751) android.os.Handler.dispatchMessage (Handler.java:95) android.os.Looper.loop (Looper.java:154) android.app.ActivityThread.main (ActivityThread.java:6165) java.lang.reflect.Method.invoke (собственный метод) com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:888) com.android.internal.os.ZygoteInit. main (ZygoteInit.java:778) JS: вызвано: java.lang.ClassNotFoundException: com.github.pires.ob ...

Я захожу в класс так:

declare var com: any;
declare var java: any;
declare var android: any;

export interface Item {
    name: string,
    text: string
}

@Component({
    selector: "ns-items",
    moduleId: module.id,
    templateUrl: "./items.component.html"
})
export class ItemsComponent implements OnInit {

private service: any;

private stats: ObservableArray<Item>;

reader: any;

constructor() {
    this.stats = new ObservableArray([]);

    let ObdGatewayService = com.github.pires.obd.reader.io.ObdGatewayService;

    this.service = new ObdGatewayService(app.android.foregroundActivity);
}

Мой файл AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.pires.obd.reader"
android:versionCode="13"
android:versionName="2.0-RC2">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.READ_LOGS" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_btcar"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    <activity
        android:name="com.github.pires.obd.reader.activity.MainActivity"
        android:configChanges="orientation|screenSize"
        android:launchMode="singleInstance"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name="com.github.pires.obd.reader.activity.ConfigActivity"
        android:launchMode="singleInstance"
        android:label="@string/app_name"></activity>
    <activity
        android:name="com.github.pires.obd.reader.activity.TroubleCodesActivity"
        android:launchMode="singleInstance"
        android:label="@string/title_activity_trouble_codes"></activity>

    <activity
        android:name="com.github.pires.obd.reader.activity.TripListActivity"
        android:launchMode="singleInstance"
        android:label="@string/title_activity_trips_list"></activity>

    <service
        android:name="com.github.pires.obd.reader.io.ObdGatewayService"
        android:launchMode="singleInstance"
        android:exported="false" />
    <service
        android:name="com.github.pires.obd.reader.io.MockObdGatewayService"
        android:launchMode="singleInstance"
        android:exported="false" />
</application>

</manifest>

Мой файл build.gradle:

buildscript {
repositories {
    mavenCentral()
    google()
    jcenter()
}
dependencies {
    classpath 'com.android.tools.build:gradle:3.3.1'
}
}

repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
}

//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'

repositories {
mavenLocal()
mavenCentral()
google()
jcenter()
}

android {
compileSdkVersion 28
defaultConfig {
    minSdkVersion 14
    //applicationId 'com.github.pires.obd.reader'

    javaCompileOptions {
        annotationProcessorOptions {
            includeCompileClasspath true
        }
    }
}
lintOptions {
    abortOnError false
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard- 
android.txt'), 'proguard-rules.pro'
    }
}

/*libraryVariants.all { variant ->
    variant.outputs.all { output ->
        if (outputFile != null && outputFileName.endsWith('.aar')) {
            outputFileName = "${archivesBaseName}-${version}.aar"
        }
    }
}*/

/*compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}*/

buildToolsVersion '28.0.3'
}

dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.github.pires:obd-java-api:1.0-RC16'
implementation 'org.roboguice:roboguice:3.+'
//annotationProcessor 'org.roboguice:roboblender:3.+'
compileOnly 'org.roboguice:roboblender:3.+'
implementation 'com.squareup.retrofit:retrofit:1.9.0'
}

Мой класс com.github.pires.obd.reader.io.ObdGatewayService в файл AAR:

package com.github.pires.obd.reader.io;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import com.github.pires.obd.commands.fuel.FuelLevelCommand;
import com.github.pires.obd.commands.control.DistanceSinceCCCommand;
import com.github.pires.obd.commands.protocol.EchoOffCommand;
import com.github.pires.obd.commands.protocol.LineFeedOffCommand;
import com.github.pires.obd.commands.protocol.ObdResetCommand;
import com.github.pires.obd.commands.protocol.SelectProtocolCommand;
import com.github.pires.obd.commands.protocol.TimeoutCommand;
import com.github.pires.obd.commands.temperature.AmbientAirTemperatureCommand;
import com.github.pires.obd.enums.ObdProtocols;
import com.github.pires.obd.exceptions.UnsupportedCommandException;
import com.github.pires.obd.reader.R;
import com.github.pires.obd.reader.activity.ConfigActivity;
import com.github.pires.obd.reader.activity.MainActivity;
import    com.github.pires.obd.reader.io.ObdCommandJob.ObdCommandJobState;
import com.google.inject.Inject;

import java.io.File;
import java.io.IOException;

/**
* This service is primarily responsible for establishing and maintaining a
* permanent connection between the device where the application runs and a more
* OBD Bluetooth interface.
* <p/>
* Secondarily, it will serve as a repository of ObdCommandJobs and at the same
* time the application state-machine.
*/
public class ObdGatewayService extends AbstractGatewayService {

private static final String TAG = ObdGatewayService.class.getName();
@Inject
SharedPreferences prefs;

private BluetoothDevice dev = null;
private BluetoothSocket sock = null;

public void startService() throws IOException {
    Log.d(TAG, "Starting service..");

    // get the remote Bluetooth device
    final String remoteDevice = prefs.getString(ConfigActivity.BLUETOOTH_LIST_KEY, null);
    if (remoteDevice == null || "".equals(remoteDevice)) {
        Toast.makeText(ctx, getString(R.string.text_bluetooth_nodevice), Toast.LENGTH_LONG).show();

        // log error
        Log.e(TAG, "No Bluetooth device has been selected.");

        // TODO kill this service gracefully
        stopService();
        throw new IOException();
    } else {

        final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        dev = btAdapter.getRemoteDevice(remoteDevice);


/*
 * Establish Bluetooth connection
 *
 * Because discovery is a heavyweight procedure for the Bluetooth adapter,
 * this method should always be called before attempting to connect to a
 * remote device with connect(). Discovery is not managed by the Activity,
 * but is run as a system service, so an application should always call
 * cancel discovery even if it did not directly request a discovery, just to
 * be sure. If Bluetooth state is not STATE_ON, this API will return false.
 *
 * see
 * http://developer.android.com/reference/android/bluetooth/BluetoothAdapter
 * .html#cancelDiscovery()
 */
        Log.d(TAG, "Stopping Bluetooth discovery.");
        btAdapter.cancelDiscovery();

        showNotification(getString(R.string.notification_action), getString(R.string.service_starting), R.drawable.ic_btcar, true, true, false);

        try {
            startObdConnection();
        } catch (Exception e) {
            Log.e(
                    TAG,
                    "There was an error while establishing connection. -> "
                            + e.getMessage()
            );

            // in case of failure, stop this service.
            stopService();
            throw new IOException();
        }
        showNotification(getString(R.string.notification_action), getString(R.string.service_started), R.drawable.ic_btcar, true, true, false);
    }
}

/**
 * Start and configure the connection to the OBD interface.
 * <p/>
 * See http://stackoverflow.com/questions/18657427/ioexception-read-failed-socket-might-closed-bluetooth-on-android-4-3/18786701#18786701
 *
 * @throws IOException
 */
private void startObdConnection() throws IOException {
    Log.d(TAG, "Starting OBD connection..");
    isRunning = true;
    try {
        sock = BluetoothManager.connect(dev);
    } catch (Exception e2) {
        Log.e(TAG, "There was an error while establishing Bluetooth connection. Stopping app..", e2);
        stopService();
        throw new IOException();
    }

    // Let's configure the connection.
    Log.d(TAG, "Queueing jobs for connection configuration..");
    queueJob(new ObdCommandJob(new ObdResetCommand()));

    //Below is to give the adapter enough time to reset before sending the commands, otherwise the first startup commands could be ignored.
    try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }

    queueJob(new ObdCommandJob(new EchoOffCommand()));

/*
 * Will send second-time based on tests.
 *
 * TODO this can be done w/o having to queue jobs by just issuing
 * command.run(), command.getResult() and validate the result.
 */
    queueJob(new ObdCommandJob(new EchoOffCommand()));
    queueJob(new ObdCommandJob(new FuelLevelCommand()));
    queueJob(new ObdCommandJob(new DistanceSinceCCCommand()));
    //queueJob(new ObdCommandJob(new LineFeedOffCommand()));
    //queueJob(new ObdCommandJob(new TimeoutCommand(62)));

    // Get protocol from preferences
    final String protocol = prefs.getString(ConfigActivity.PROTOCOLS_LIST_KEY, "AUTO");
    queueJob(new ObdCommandJob(new SelectProtocolCommand(ObdProtocols.valueOf(protocol))));

    // Job for returning dummy data
    //queueJob(new ObdCommandJob(new AmbientAirTemperatureCommand()));

    queueCounter = 0L;
    Log.d(TAG, "Initialization jobs queued.");


}

/**
 * This method will add a job to the queue while setting its ID to the
 * internal queue counter.
 *
 * @param job the job to queue.
 */
@Override
public void queueJob(ObdCommandJob job) {
    // This is a good place to enforce the imperial units option
    job.getCommand().useImperialUnits(prefs.getBoolean(ConfigActivity.IMPERIAL_UNITS_KEY, false));

    // Now we can pass it along
    super.queueJob(job);
}

/**
 * Runs the queue until the service is stopped
 */
protected void executeQueue() throws InterruptedException {
    Log.d(TAG, "Executing queue..");
    while (!Thread.currentThread().isInterrupted()) {
        ObdCommandJob job = null;
        try {
            job = jobsQueue.take();

            // log job
            Log.d(TAG, "Taking job[" + job.getId() + "] from queue..");

            if (job.getState().equals(ObdCommandJobState.NEW)) {
                Log.d(TAG, "Job state is NEW. Run it..");
                job.setState(ObdCommandJobState.RUNNING);
                if (sock.isConnected()) {
                    job.getCommand().run(sock.getInputStream(), sock.getOutputStream());
                } else {
                    job.setState(ObdCommandJobState.EXECUTION_ERROR);
                    Log.e(TAG, "Can't run command on a closed socket.");
                }
            } else
                // log not new job
                Log.e(TAG,
                        "Job state was not new, so it shouldn't be in queue. BUG ALERT!");
        } catch (InterruptedException i) {
            Thread.currentThread().interrupt();
        } catch (UnsupportedCommandException u) {
            if (job != null) {
                job.setState(ObdCommandJobState.NOT_SUPPORTED);
            }
            Log.d(TAG, "Command not supported. -> " + u.getMessage());
        } catch (IOException io) {
            if (job != null) {
                if(io.getMessage().contains("Broken pipe"))
                    job.setState(ObdCommandJobState.BROKEN_PIPE);
                else
                    job.setState(ObdCommandJobState.EXECUTION_ERROR);
            }
            Log.e(TAG, "IO error. -> " + io.getMessage());
        } catch (Exception e) {
            if (job != null) {
                job.setState(ObdCommandJobState.EXECUTION_ERROR);
            }
            Log.e(TAG, "Failed to run command. -> " + e.getMessage());
        }

        if (job != null) {
            final ObdCommandJob job2 = job;
            ((MainActivity) ctx).runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    ((MainActivity) ctx).stateUpdate(job2);
                }
            });
        }
    }
}

/**
 * Stop OBD connection and queue processing.
 */
public void stopService() {
    Log.d(TAG, "Stopping service..");

    notificationManager.cancel(NOTIFICATION_ID);
    jobsQueue.clear();
    isRunning = false;

    if (sock != null)
        // close socket
        try {
            sock.close();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }

    // kill service
    stopSelf();
}

public boolean isRunning() {
    return isRunning;
}

public static void saveLogcatToFile(Context context, String devemail) {
    Intent emailIntent = new Intent(Intent.ACTION_SEND);
    emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    emailIntent.setType("text/plain");
    emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{devemail});
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "OBD2 Reader Debug Logs");

    StringBuilder sb = new StringBuilder();
    sb.append("\nManufacturer: ").append(Build.MANUFACTURER);
    sb.append("\nModel: ").append(Build.MODEL);
    sb.append("\nRelease: ").append(Build.VERSION.RELEASE);

    emailIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());

    String fileName = "OBDReader_logcat_" + System.currentTimeMillis() + ".txt";
    File sdCard = Environment.getExternalStorageDirectory();
    File dir = new File(sdCard.getAbsolutePath() + File.separator + "OBD2Logs");
    if (dir.mkdirs()) {
        File outputFile = new File(dir, fileName);
        Uri uri = Uri.fromFile(outputFile);
        emailIntent.putExtra(Intent.EXTRA_STREAM, uri);

        Log.d("savingFile", "Going to save logcat to " + outputFile);
        //emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(Intent.createChooser(emailIntent, "Pick an Email provider").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

        try {
            @SuppressWarnings("unused")
            Process process = Runtime.getRuntime().exec("logcat -f " + outputFile.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

}
...