开发Android Studio VPN应用程序时出现错误消息

在开发Open VPN应用程序时出现以下消息:07-04 21:33:34.998 20337-21875 / pioneers.safwat.myvpn6 E / AndroidRuntime:致命异常:OpenVPNManagementThread java.lang.UnsatisfiedLinkError:未找到本地方法:pioneers.safwat .myvpn6.NativeUtils.jniclose:(I)V at pioneers.safwat.myvpn6.NativeUtils.jniclose(Native Method)at pioneers.safwat.myvpn6.OpenVpnManagementThread.protectFileDescriptor(OpenVpnManagementThread.java:175)at pioneers.safwat.myvpn6.OpenVpnManagementThread .processNeedCommand(OpenVpnManagementThread.java:387)at pioneers.safwat.myvpn6.OpenVpnManagementThread.processCommand(OpenVpnManagementThread.java:227)at pioneers.safwat.myvpn6.OpenVpnManagementThread.processInput(OpenVpnManagementThread.java:198)at pioneers.safwat.myvpn6。 OpenVpnManagementThread.run(OpenVpnManagementThread.java:146)at java.lang.Thread.run(Thread.java:841)07-04 21:33:35.288 20337-20337 / pioneers.safwat.myvpn6 E / ActivityThread:Activity pioneers.safwat .myvpn6.MainActiv ity_vpn已经泄露了ServiceConnection pioneers.safwat.myvpn6.MainActivity_vpn$1@42537e00这是最初绑定在这里android.app.ServiceConnectionLeaked:活动pioneers.safwat.myvpn6.MainActivity_vpn泄漏了ServiceConnection pioneers.safwat.myvpn6.MainActivity_vpn$1@42537e00最初绑定这里android.app.LoadedApk $ ServiceDispatcher。(LoadedApk.java:979)在android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:873)在android.app.ContextImpl.bindServiceAsUser(ContextImpl.java:1850)在android。 app.ContextImpl.bindService(ContextImpl.java:1838)at android.content.ContextWrapper.bindService(ContextWrapper.java:503)at pioneers.safwat.myvpn6.MainActivity_vpn.onCreate(MainActivity_vpn.java:53)at android.app.Activity .performCreate(Activity.java:5372)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270)

Nativeutilis类:

public class NativeUtils {
    public static native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
    public static native String[] getIfconfig() throws  IllegalArgumentException;
    static native void jniclose(int fdint);

    static {
    //  System.loadLibrary("opencv_java");
        System.loadLibrary("stlport_shared");
        System.loadLibrary("opvpnutil");
        System.loadLibrary("openvpn");
        System.loadLibrary("ssl");
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN)
        System.loadLibrary("crypto");
    }
}

OpenVpnManagementThread类:

   public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {

    private static final String TAG = "Durai";
    private LocalSocket mSocket;
    private VpnProfile mProfile;
    private OpenVPNService mOpenVPNService;
    private LinkedList<FileDescriptor> mFDList = new LinkedList<FileDescriptor>();
    private LocalServerSocket mServerSocket;
    private boolean mReleaseHold = true;
    private boolean mWaitingForRelease = false;
    private long mLastHoldRelease = 0;

    private static final Vector<OpenVpnManagementThread> active = new Vector<OpenVpnManagementThread>();
    private LocalSocket mServerSocketLocal;

    private pauseReason lastPauseReason = pauseReason.noNetwork;

    public OpenVpnManagementThread(VpnProfile profile, OpenVPNService openVpnService) {
        mProfile = profile;
        mOpenVPNService = openVpnService;


        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(openVpnService);
        boolean managemeNetworkState = prefs.getBoolean("netchangereconnect", true);
        if (managemeNetworkState)
            mReleaseHold = false;

    }

    public boolean openManagementInterface(@NotNull Context c) {
        // Could take a while to open connection
        int tries = 8;

        String socketName = (c.getCacheDir().getAbsolutePath() + "/" + "mgmtsocket");
        // The mServerSocketLocal is transferred to the LocalServerSocket, ignore warning

        mServerSocketLocal = new LocalSocket();

        while (tries > 0 && !mServerSocketLocal.isConnected()) {
            try {
                mServerSocketLocal.bind(new LocalSocketAddress(socketName,
                        LocalSocketAddress.Namespace.FILESYSTEM));
            } catch (IOException e) {
                // wait 300 ms before retrying
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e1) {
                }

            }
            tries--;
        }

        try {

            mServerSocket = new LocalServerSocket(mServerSocketLocal.getFileDescriptor());
            return true;
        } catch (IOException e) {
            VpnStatus.logException(e);
        }
        return false;


    }

    public void managmentCommand(String cmd) {
        try {
            if (mSocket != null && mSocket.getOutputStream() != null) {
                mSocket.getOutputStream().write(cmd.getBytes());
                mSocket.getOutputStream().flush();
            }
        } catch (IOException e) {
            // Ignore socket stack traces
        }
    }


    @Override
    public void run() {
        byte[] buffer = new byte[2048];
        //  mSocket.setSoTimeout(5); // Setting a timeout cannot be that bad

        String pendingInput = "";
        synchronized (active) {
            active.add(this);
        }

        try {
            // Wait for a client to connect
            mSocket = mServerSocket.accept();
            InputStream instream = mSocket.getInputStream();
            // Close the management socket after client connected

            mServerSocket.close();
            // Closing one of the two sockets also closes the other
            //mServerSocketLocal.close();

            while (true) {
                int numbytesread = instream.read(buffer);
                if (numbytesread == -1)
                    return;

                FileDescriptor[] fds = null;
                try {
                    fds = mSocket.getAncillaryFileDescriptors();
                } catch (IOException e) {
                    VpnStatus.logException("Error reading fds from socket", e);
                }
                if (fds != null) {
                    Collections.addAll(mFDList, fds);
                }

                String input = new String(buffer, 0, numbytesread, "UTF-8");

                pendingInput += input;

                pendingInput = processInput(pendingInput);


            }
        } catch (IOException e) {
            if (!e.getMessage().equals("socket closed") && !e.getMessage().equals("Connection reset by peer"))
                VpnStatus.logException(e);
        }
        synchronized (active) {
            active.remove(this);
        }
    }

    //! Hack O Rama 2000!
    private void protectFileDescriptor(FileDescriptor fd) {
        Exception exp;
        try {
            Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$");
            int fdint = (Integer) getInt.invoke(fd);
            boolean result = mOpenVPNService.protect(fdint);
            if (!result)
                VpnStatus.logWarning("Could not protect VPN socket");
            NativeUtils.jniclose(fdint);
            return;
        } catch (NoSuchMethodException e) {
            exp = e;
        } catch (IllegalArgumentException e) {
            exp = e;
        } catch (IllegalAccessException e) {
            exp = e;
        } catch (InvocationTargetException e) {
            exp = e;
        } catch (NullPointerException e) {
            exp = e;
        }

        Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd);
        VpnStatus.logException("Failed to retrieve fd from socket (" + fd + ")", exp);
    }

    private String processInput(String pendingInput) {


        while (pendingInput.contains("n")) {
            String[] tokens = pendingInput.split("r?n", 2);
            processCommand(tokens[0]);
            if (tokens.length == 1)
                // No second part, newline was at the end
                pendingInput = "";
            else
                pendingInput = tokens[1];
        }
        return pendingInput;
    }


    private void processCommand(String command) {
        //Log.i(TAG, "Line from managment" + command);


        if (command.startsWith(">") && command.contains(":")) {
            String[] parts = command.split(":", 2);
            String cmd = parts[0].substring(1);
            String argument = parts[1];


            if (cmd.equals("INFO")) {
                /* Ignore greeting from management */
                return;
            } else if (cmd.equals("PASSWORD")) {
                processPWCommand(argument);
            } else if (cmd.equals("HOLD")) {
                handleHold();
            } else if (cmd.equals("NEED-OK")) {
                processNeedCommand(argument);
            } else if (cmd.equals("BYTECOUNT")) {
                processByteCount(argument);
            } else if (cmd.equals("STATE")) {
                processState(argument);
            } else if (cmd.equals("PROXY")) {
                processProxyCMD(argument);
            } else if (cmd.equals("LOG")) {
                processLogMessage(argument);
            } else if (cmd.equals("RSA_SIGN")) {
                processSignCommand(argument);
            } else {
                VpnStatus.logWarning("MGMT: Got unrecognized command" + command);
                Log.i(TAG, "Got unrecognized command" + command);
            }
        } else if (command.startsWith("SUCCESS:")) {
            /* Ignore this kind of message too */
            return;
        } else if (command.startsWith("PROTECTFD: ")) {
            FileDescriptor fdtoprotect = mFDList.pollFirst();
            if (fdtoprotect != null)
                protectFileDescriptor(fdtoprotect);
        } else {
            Log.i(TAG, "Got unrecognized line from managment" + command);
            VpnStatus.logWarning("MGMT: Got unrecognized line from management:" + command);
        }
    }

    private void processLogMessage(String argument) {
        String[] args = argument.split(",", 4);
        Log.d("OpenVPN", argument);

        VpnStatus.LogLevel level;
        if (args[1].equals("I")) {
            level = VpnStatus.LogLevel.INFO;
        } else if (args[1].equals("W")) {
            level = VpnStatus.LogLevel.WARNING;
        } else if (args[1].equals("D")) {
            level = VpnStatus.LogLevel.VERBOSE;
        } else if (args[1].equals("F")) {
            level = VpnStatus.LogLevel.ERROR;
        } else {
            level = VpnStatus.LogLevel.INFO;
        }

        int ovpnlevel = Integer.parseInt(args[2]) & 0x0F;
        String msg = args[3];

        if (msg.startsWith("MANAGEMENT: CMD"))
            ovpnlevel = Math.max(4, ovpnlevel);

        VpnStatus.logMessageOpenVPN(level, ovpnlevel, msg);
    }

    private void handleHold() {
        if (mReleaseHold) {
            releaseHoldCmd();
        } else {
            mWaitingForRelease = true;
            VpnStatus.updateStatePause(lastPauseReason);

        }
    }

    private void releaseHoldCmd() {
        if ((System.currentTimeMillis() - mLastHoldRelease) < 5000) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ignored) {
            }

        }
        mWaitingForRelease = false;
        mLastHoldRelease = System.currentTimeMillis();
        managmentCommand("hold releasen");
        managmentCommand("bytecount " + mBytecountInterval + "n");
        managmentCommand("state onn");
    }

    public void releaseHold() {
        mReleaseHold = true;
        if (mWaitingForRelease)
            releaseHoldCmd();

    }

    private void processProxyCMD(String argument) {
        String[] args = argument.split(",", 3);
        SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile);


        if (args.length >= 2) {
            String proto = args[1];
            if (proto.equals("UDP")) {
                proxyaddr = null;
            }
        }

        if (proxyaddr instanceof InetSocketAddress) {
            InetSocketAddress isa = (InetSocketAddress) proxyaddr;

            VpnStatus.logInfo(R.string.using_proxy, isa.getHostName(), isa.getPort());

            String proxycmd = String.format(Locale.ENGLISH, "proxy HTTP %s %dn", isa.getHostName(), isa.getPort());
            managmentCommand(proxycmd);
        } else {
            managmentCommand("proxy NONEn");
        }

    }

    private void processState(String argument) {
        String[] args = argument.split(",", 3);
        String currentstate = args[1];

        if (args[2].equals(",,"))
            VpnStatus.updateStateString(currentstate, "");
        else
            VpnStatus.updateStateString(currentstate, args[2]);
    }


    private void processByteCount(String argument) {
        //   >BYTECOUNT:{BYTES_IN},{BYTES_OUT}
        int comma = argument.indexOf(',');
        long in = Long.parseLong(argument.substring(0, comma));
        long out = Long.parseLong(argument.substring(comma + 1));
        VpnStatus.updateByteCount(in, out);
    }
    private void processNeedCommand(String argument) {
        int p1 = argument.indexOf(''');
        int p2 = argument.indexOf(''', p1 + 1);
        String needed = argument.substring(p1 + 1, p2);
        String extra = argument.split(":", 2)[1];
        String status = "ok";
        if (needed.equals("PROTECTFD")) {
            FileDescriptor fdtoprotect = mFDList.pollFirst();
            protectFileDescriptor(fdtoprotect);
        } else if (needed.equals("DNSSERVER")) {
            mOpenVPNService.addDNS(extra);
        } else if (needed.equals("DNSDOMAIN")) {
            mOpenVPNService.setDomain(extra);
        } else if (needed.equals("ROUTE")) {
            String[] routeparts = extra.split(" ");

            if (routeparts.length == 5) {
                if (BuildConfig.DEBUG) Assert.assertEquals("dev", routeparts[3]);
                mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]);
            } else if (routeparts.length >= 3) {
                mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null);
            } else {
                VpnStatus.logError("Unrecognized ROUTE cmd:" + Arrays.toString(routeparts) + " | " + argument);
            }

        } else if (needed.equals("ROUTE6")) {
            String[] routeparts = extra.split(" ");
            mOpenVPNService.addRoutev6(routeparts[0], routeparts[1]);
        } else if (needed.equals("IFCONFIG")) {
            String[] ifconfigparts = extra.split(" ");
            int mtu = Integer.parseInt(ifconfigparts[2]);
            mOpenVPNService.setLocalIP(ifconfigparts[0], ifconfigparts[1], mtu, ifconfigparts[3]);
        } else if (needed.equals("IFCONFIG6")) {
            mOpenVPNService.setLocalIPv6(extra);

        } else if (needed.equals("PERSIST_TUN_ACTION")) {
            // check if tun cfg stayed the same
            status = mOpenVPNService.getTunReopenStatus();
        } else if (needed.equals("OPENTUN")) {
            if (sendTunFD(needed, extra))
                return;
            else
                status = "cancel";
        } else {
            Log.e(TAG, "Unkown needok command " + argument);
            return;
        }
        String cmd = String.format("needok '%s' %sn", needed, status);
        managmentCommand(cmd);
    }
    private boolean sendTunFD(String needed, String extra) {
        Exception exp;
        if (!extra.equals("tun")) {
            VpnStatus.logError(String.format("Device type %s requested, but only tun is possible with the Android API, sorry!", extra));
            return false;
        }
        ParcelFileDescriptor pfd = mOpenVPNService.openTun();
        if (pfd == null)
            return false;

        Method setInt;
        int fdint = pfd.getFd();
        try {
            setInt = FileDescriptor.class.getDeclaredMethod("setInt$", int.class);
            FileDescriptor fdtosend = new FileDescriptor();
            setInt.invoke(fdtosend, fdint);
            FileDescriptor[] fds = {fdtosend};
            mSocket.setFileDescriptorsForSend(fds);
            String cmd = String.format("needok '%s' %sn", needed, "ok");
            managmentCommand(cmd);
            mSocket.setFileDescriptorsForSend(null);
            pfd.close();
            return true;
        } catch (NoSuchMethodException e) {
            exp = e;
        } catch (IllegalArgumentException e) {
            exp = e;
        } catch (IllegalAccessException e) {
            exp = e;
        } catch (InvocationTargetException e) {
            exp = e;
        } catch (IOException e) {
            exp = e;
        }
        VpnStatus.logException("Could not send fd over socket", exp);
        return false;
    }

    private void processPWCommand(String argument) {
        String needed;
        try {

            int p1 = argument.indexOf(''');
            int p2 = argument.indexOf(''', p1 + 1);
            needed = argument.substring(p1 + 1, p2);
            if (argument.startsWith("Verification Failed")) {
                proccessPWFailed(needed, argument.substring(p2 + 1));
                return;
            }
        } catch (StringIndexOutOfBoundsException sioob) {
            VpnStatus.logError("Could not parse management Password command: " + argument);
            return;
        }
        String pw = null;

        if (needed.equals("Private Key")) {
            pw = mProfile.getPasswordPrivateKey();
        } else if (needed.equals("Auth")) {
            String usercmd = String.format("username '%s' %sn",
                    needed, VpnProfile.openVpnEscape(mProfile.mUsername));
            managmentCommand(usercmd);
            pw = mProfile.getPasswordAuth();
        }
        if (pw != null) {
            String cmd = String.format("password '%s' %sn", needed, VpnProfile.openVpnEscape(pw));
            managmentCommand(cmd);
        } else {
            VpnStatus.logError(String.format("Openvpn requires Authentication type '%s' but no password/key information available", needed));
        }
    }

    private void proccessPWFailed(String needed, String args) {
        VpnStatus.updateStateString("AUTH_FAILED", needed + args,R.string.state_auth_failed, VpnStatus.ConnectionStatus.LEVEL_AUTH_FAILED);
    }
    private static boolean stopOpenVPN() {
        synchronized (active) {
            boolean sendCMD = false;
            for (OpenVpnManagementThread mt : active) {
                mt.managmentCommand("signal SIGINTn");
                sendCMD = true;
                try {
                    if (mt.mSocket != null)
                        mt.mSocket.close();
                } catch (IOException e) {
                }
            }
            return sendCMD;
        }
    }

    @Override
    public void networkChange() {
        if (!mWaitingForRelease)
            managmentCommand("network-changen");
    }

    public void signalusr1() {
        mReleaseHold = false;

        if (!mWaitingForRelease)
            managmentCommand("signal SIGUSR1n");
        else
            VpnStatus.updateStatePause(lastPauseReason);
    }

    public void reconnect() {
        signalusr1();
        releaseHold();
    }
    private void processSignCommand(String b64data) {
        String signed_string = mProfile.getSignedData(b64data);
        if (signed_string == null) {
            managmentCommand("rsa-sign");
            managmentCommand("nENDn");
            stopOpenVPN();
            return;
        }
        managmentCommand("rsa-sign");
        managmentCommand(signed_string);
        managmentCommand("nENDn");
    }
    @Override
    public void pause(pauseReason reason) {
        lastPauseReason = reason;
        signalusr1();
    }

    @Override
    public void resume() {
        releaseHold();
        /* Reset the reason why we are disconnected */
        lastPauseReason = pauseReason.noNetwork;
    }
    @Override
    public boolean stopVPN() {
        return stopOpenVPN();
    }
}

MainActivity_vpn类:

public class MainActivity_vpn extends Activity {
protected OpenVPNService mService;
boolean mBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className,
                                   IBinder service) {
        OpenVPNService.LocalBinder binder = (OpenVPNService.LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }
    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        mService =null;
        mBound = false;
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_vpn);
    Intent intent = new Intent(getBaseContext(), OpenVPNService.class);
    intent.setAction(OpenVPNService.START_SERVICE);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    registerReceiver(broadcastReceiver, new IntentFilter("CONNECTION_CHANGE"));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    getMenuInflater().inflate(R.menu.settingsmenu, menu);
    return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    if (Constants.isVPNConnected){
        // disable connect button if VPN is connected
        menu.getItem(0).setEnabled(false);
        // enable disconnect button if VPN is connected
        menu.getItem(1).setEnabled(true);
    } else{
        // enable connect button if VPN is disconnected
        menu.getItem(0).setEnabled(true);
        // disable disconnect button if VPN is disconnected
        menu.getItem(1).setEnabled(false);
    }
    return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case R.id.action_startvpn:
            configureAndStartVpn() ;
            return true ;
        case R.id.action_stopvpn:
            stopVPN() ;
            return true ;
        case R.id.action_removeProfile:
            removeProfile();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
private void removeProfile() {

    final ProfileManager pm = ProfileManager.getInstance(MainActivity_vpn.this) ;
    final VpnProfile profile = pm.getProfileByName(Constants.VPN_PROFILE_NAME) ;

    if (profile != null) {
                        stopVPN() ;
                        pm.removeProfile(getApplicationContext(),profile);
                        int duration = Toast.LENGTH_SHORT;
                        Toast toast = Toast.makeText(MainActivity_vpn.this,"The VPN Configuration is deleted", duration);
                        toast.show();
    } else {
                int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(MainActivity_vpn.this,"There are no VPN Configurations to delete", duration);toast.show();
    }
}
private void stopVPN() {
    try{
        ProfileManager.setConntectedVpnProfileDisconnected(MainActivity_vpn.this);
        if(mService.getManagement()!=null)
            mService.getManagement().stopVPN();
    }
    catch (Exception ex){
    }
}
private void configureAndStartVpn() {
    try {
                EditText Et_Ovpn = (EditText) findViewById(R.id.et_ovpn);

                String retVal = Et_Ovpn.getText().toString();

                if (retVal != null && retVal.trim().length()>0) {

                    byte[] buffer = retVal.getBytes() ;

                    VpnProfile vp = saveProfile(buffer) ;

                    if (vp != null) {
                        startVPN(vp) ;
                    }
                }
                else {
                    int duration = Toast.LENGTH_LONG;
                    Toast toast = Toast.makeText(MainActivity_vpn.this,"Connecting using the last vpn configuration", duration);
                    toast.show();
                    startVPN();
                }
    } catch (Exception e) {
        e.printStackTrace() ;
    }
}
private VpnProfile saveProfile(byte [] data) {

    ConfigParser cp = new ConfigParser();
    try {
        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(data));
        cp.parseConfig(isr);
        VpnProfile vp = cp.convertProfile();
        ProfileManager vpl = ProfileManager.getInstance(this);
        vp.mName = Constants.VPN_PROFILE_NAME ;
        vpl.addProfile(vp);
        vpl.saveProfile(this, vp);
        vpl.saveProfileList(this);
        return vp ;
    } catch(Exception e) {
        return null ;
    }
}
public void startVPN(VpnProfile vp) {
    Intent intent = new Intent(getApplicationContext(),LaunchVPN.class);
    intent.putExtra(LaunchVPN.EXTRA_KEY, vp.getUUID().toString());
    intent.setAction(Intent.ACTION_MAIN);
    startActivity(intent);
}
private void startVPN() {

    ProfileManager pm = ProfileManager.getInstance(this) ;
    VpnProfile profile = pm.getProfileByName(Constants.VPN_PROFILE_NAME) ;

    if (profile == null) {
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(MainActivity_vpn.this,"There are no VPN Configurations.So paste the .OVPN and try", duration);
        toast.show();
        return ;
    }

    Intent intent = new Intent(this,LaunchVPN.class);
    intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
    intent.setAction(Intent.ACTION_MAIN);
    startActivity(intent);
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        stopVPN();
        startVPN();
    }
};

@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(broadcastReceiver);
}

}


从你的日志中我看到了这一行:

MainActivity_vpn has leaked ServiceConnection

在你的活动OnCreate你绑定到服务,但你永远不会解除绑定。 将此添加到您的MainActivity onDestroy方法中:

    if (mServiceConn != null) {
      unbindService(mServiceConn);
    }

另请参阅:JNI java.lang.UnsatisfiedLinkError:未找到本地方法

我认为你应该从方法签名中移除静态


我没有考虑到本地方法的声明应该放在与捐助者项目相同的名称和包中。 一旦我改变了本地方法的包名,问题就解决了

链接地址: http://www.djcxy.com/p/80013.html

上一篇: Error message while developing Android Studio VPN Application

下一篇: Android connecting HTTP to MVC Asp.net Controller