ngrok / ngrok-java

Embed ngrok secure ingress into your Java apps with a single line of code.
Other
21 stars 6 forks source link

No implementation found for com.ngrok.NativeSession #50

Open benagastov opened 1 month ago

benagastov commented 1 month ago

Good afternoon. I tried to implement Ngrok in my Android Studio Project using Java-gradle to compile. But everytime I tried to run the app, it will return com.ngrok.NativeSession error due to no implementation.

No implementation found for com.ngrok.NativeSession com.ngrok.NativeSession.connectNative(com.ngrok.Session$Builder) (tried Java_com_ngrok_NativeSession_connectNative and Java_com_ngrok_NativeSession_connectNative__Lcom_ngrok_Session_00024Builder_2) FATAL EXCEPTION: Thread-2 Process: com.example.ngrokjava, PID: 20169 java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: No implementation found for com.ngrok.NativeSession com.ngrok.NativeSession.connectNative(com.ngrok.Session$Builder) (tried Java_com_ngrok_NativeSession_connectNative and Java_com_ngrok_NativeSession_connectNative__Lcom_ngrok_Session_00024Builder_2) at com.ngrok.Session.connect(Session.java:53) at com.ngrok.Session$Builder.connect(Session.java:542) at com.example.ngrokjava.MainActivity.runNgrok(MainActivity.java:47) at com.example.ngrokjava.MainActivity.lambda$onCreate$0(MainActivity.java:28) at com.example.ngrokjava.MainActivity.$r8$lambda$nPniPBgeArslOcKEjZ1t1UsHRUk(Unknown Source:0) at com.example.ngrokjava.MainActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0) at java.lang.Thread.run(Thread.java:920) Caused by: java.lang.UnsatisfiedLinkError: No implementation found for com.ngrok.NativeSession com.ngrok.NativeSession.connectNative(com.ngrok.Session$Builder) (tried Java_com_ngrok_NativeSession_connectNative and Java_com_ngrok_NativeSession_connectNative__Lcom_ngrok_Session_00024Builder_2) at com.ngrok.NativeSession.connectNative(Native Method) at com.ngrok.NativeSession.connect(NativeSession.java:45) at java.lang.reflect.Method.invoke(Native Method) at com.ngrok.Session.connect(Session.java:47) at com.ngrok.Session$Builder.connect(Session.java:542)  at com.example.ngrokjava.MainActivity.runNgrok(MainActivity.java:47)  at com.example.ngrokjava.MainActivity.lambda$onCreate$0(MainActivity.java:28)  at com.example.ngrokjava.MainActivity.$r8$lambda$nPniPBgeArslOcKEjZ1t1UsHRUk(Unknown Source:0)  at com.example.ngrokjava.MainActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)  at java.lang.Thread.run(Thread.java:920) 

nikolay-ngrok commented 4 weeks ago

Hello @benagastov, this looks like a problem with your dependencies. Can you share part of your gradle configuration that adds ngrok-java as a dependency? You'll need to include the correct ngrok-java-native for your platform.

benagastov commented 3 weeks ago

Pardon me for my late response. Here is my gradle code in Android Studio:

    alias(libs.plugins.android.application)
    id("com.google.osdetector").version("1.7.3")
}

android {
    namespace 'com.example.ngrokjava'
    compileSdk 34

    defaultConfig {
        applicationId "com.example.ngrokjava"
        minSdk 24
        targetSdk 34
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}

dependencies {

    implementation libs.appcompat
    implementation("com.ngrok:ngrok-java:0.4.0")
    implementation("com.ngrok:ngrok-java-native:0.4.0:linux-android-arm64-v8a")
    implementation libs.material
    implementation libs.activity
    implementation libs.constraintlayout
    testImplementation libs.junit
    androidTestImplementation libs.ext.junit
    androidTestImplementation libs.espresso.core
}```

My Main Activity java class:
```package com.example.ngrokjava;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.ngrok.Session;
import com.ngrok.Http;

import java.io.IOException;
import java.nio.ByteBuffer;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);

        // Call ngrok execution after ViewCompat setup
        new Thread(() -> {
            try {
                runNgrok();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
    }

    private void runNgrok() throws IOException {
        // Session.withAuthtokenFromEnv() will create a new session builder, pulling NGROK_AUTHTOKEN env variable.
        // You can get your authtoken by registering at https://dashboard.ngrok.com
        var sessionBuilder = Session.withAuthtokenFromEnv().metadata("my session");
        // Session.Builder let you customize different aspects of the session, see docs for details.
        // After customizing the builder, you connect:
        try (var session = sessionBuilder.connect()) {
            // Creates and configures http listener that will be using oauth to secure it
            var listenerBuilder = session.httpEndpoint().metadata("my listener")
                    .oauthOptions(new Http.OAuth("google"));
            // Now start listening with the above configuration
            try (var listener = listenerBuilder.listen()) {
                System.out.println("ngrok url: " + listener.getUrl());
                var buf = ByteBuffer.allocateDirect(1024);

                while (true) {
                    // Accept a new connection
                    var conn = listener.accept();

                    // Read from the connection
                    conn.read(buf);

                    System.out.println(buf.asCharBuffer());

                    // Or write to it
                    conn.write(buf);
                }
            }
        }
    }
}
nikolay-ngrok commented 3 weeks ago

One thing I noticed in your gradle script is using a target we don't produce:

implementation("com.ngrok:ngrok-java-native:0.4.0:linux-android-arm64-v8a")

You should probably try the one we have:

implementation("com.ngrok:ngrok-java-native:0.4.0:linux-android-aarch_64")

Also, the latest version of the sdk is 1.0.1, so maybe you could try that (as opposed to using 0.4.0) 👍