3

I wanna to create an HTTP server in Android. I want to use com.sun.net.httpserver in this program. In your opinion, Is it possible to use this package in Android program? I wrote a service to do this. My program is as fallow:

import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

public class HSMainService extends Service {

    //region constants
    public static final int MY_NOTIFICATION_ID = 1;
    public static final int SERVERPORT = 8080;
    //endregion
    //************************
    //region instance variables
    private String TAG;
    private Uri soundURI = Uri
            .parse("android.resource://com.ebcompany.hs4/"
                    + R.raw.alarm_rooster);
    private long[] mVibratePattern = { 0, 200, 200, 300 };

    private HttpServer server;
    //endregion
    //************************
    //region constructors
    public HSMainService() {
        //TAG = getApplicationContext().getString(R.string.log_message_tag);
    }
    //endregion
    //************************
    //region override methods
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    // This is the old onStart method that will be called on the pre-2.0
    // platform.  On 2.0 or later we override onStartCommand() so this
    // method will not be called.
    @Override
    public void onStart(Intent intent, int startId) {
        //handleCommand(intent);
        Log.i(TAG, "onStart");
        Toast.makeText(getApplicationContext(), "onStart", Toast.LENGTH_LONG).show();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //handleCommand(intent);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        Log.i(TAG, "onStartCommand");
        //Intent in = new Intent(getApplicationContext(), TestActivity.class);
        //in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //startActivity(in);
        //Toast.makeText(getApplicationContext(), "onStartCommand", Toast.LENGTH_LONG).show();
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Context cntx = getApplicationContext();
        TAG = cntx.getString(R.string.log_message_tag);
        Log.i(TAG, "Service creating");
        final Notification.Builder notificationBuilder = new    Notification.Builder(getApplicationContext())
                .setContentInfo("HS4")
                .setSmallIcon(R.drawable.icon)
                .setContentTitle(cntx.getString(R.string.notification_content_title))
                .setContentText(cntx.getString(R.string.notification_content_text))
                .setTicker(cntx.getString(R.string.notification_tiker_text))
                .setSound(soundURI)
                .setOngoing(true)
                .setLargeIcon((((BitmapDrawable)    this.getResources().getDrawable(R.drawable.fire_eye_alien)).getBitmap()));
        final NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationBuilder.setWhen(System.currentTimeMillis());
        mNotificationManager.notify(MY_NOTIFICATION_ID,
                notificationBuilder.build());
        try {
            server = HttpServer.create(new InetSocketAddress(SERVERPORT), 0);
            server.createContext("IS2", new IS2Handler());
            server.createContext("DSP", new DSPHandler());
            server.setExecutor(Executors.newFixedThreadPool(0x5) ); // creates a default executor
            server.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "Service destroying");
        //server.stop(0x1);
    }
    //endregion
    //************************
}

When I run this program I get this error:

08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 I/dalvikvm﹕ Could not find method sun.misc.Service.providers, referenced from method com.sun.net.httpserver.spi.HttpServerProvider.loadProviderAsService
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 W/dalvikvm﹕ VFY: unable to resolve static method 421: Lsun/misc/Service;.providers (Ljava/lang/Class;Ljava/lang/ClassLoader;)Ljava/util/Iterator;
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 E/dalvikvm﹕ Could not find class 'sun.misc.ServiceConfigurationError', referenced from method com.sun.net.httpserver.spi.HttpServerProvider.loadProviderFromProperty
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 W/dalvikvm﹕ VFY: unable to resolve new-instance 155 (Lsun/misc/ServiceConfigurationError;) in Lcom/sun/net/httpserver/spi/HttpServerProvider;
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 E/dalvikvm﹕ Could not find class 'sun.misc.ServiceConfigurationError', referenced from method com.sun.net.httpserver.spi.HttpServerProvider.loadProviderFromProperty
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 W/dalvikvm﹕ VFY: unable to resolve new-instance 155 (Lsun/misc/ServiceConfigurationError;) in Lcom/sun/net/httpserver/spi/HttpServerProvider;
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 E/dalvikvm﹕ Could not find class 'sun.misc.ServiceConfigurationError', referenced from method com.sun.net.httpserver.spi.HttpServerProvider.loadProviderFromProperty
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 W/dalvikvm﹕ VFY: unable to resolve new-instance 155 (Lsun/misc/ServiceConfigurationError;) in Lcom/sun/net/httpserver/spi/HttpServerProvider;
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 E/dalvikvm﹕ Could not find class 'sun.misc.ServiceConfigurationError', referenced from method com.sun.net.httpserver.spi.HttpServerProvider.loadProviderFromProperty
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 W/dalvikvm﹕ VFY: unable to resolve new-instance 155 (Lsun/misc/ServiceConfigurationError;) in Lcom/sun/net/httpserver/spi/HttpServerProvider;
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xacd19b20)
08-02 04:24:37.233    2994-2994/com.ebcompany.hs4 E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.ebcompany.hs4, PID: 2994
    java.lang.NoClassDefFoundError: sun.misc.Service
            at com.sun.net.httpserver.spi.HttpServerProvider.loadProviderAsService(HttpServerProvider.java:82)
            at com.sun.net.httpserver.spi.HttpServerProvider.access$200(HttpServerProvider.java:27)
            at com.sun.net.httpserver.spi.HttpServerProvider$1.run(HttpServerProvider.java:144)
            at java.security.AccessController.doPrivileged(AccessController.java:45)
            at com.sun.net.httpserver.spi.HttpServerProvider.provider(HttpServerProvider.java:139)
            at com.sun.net.httpserver.HttpServer.create(HttpServer.java:110)
            at com.ebcompany.hs4.HSMainService.onCreate(HSMainService.java:93)
            at android.app.ActivityThread.handleCreateService(ActivityThread.java:2572)
            at android.app.ActivityThread.access$1800(ActivityThread.java:135)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)

How can I solve this problem?

Arnab Nandy
  • 6,472
  • 5
  • 44
  • 50
ebi
  • 79
  • 1
  • 7
  • In addition to finding the code, there are some other issues on Android - keeping the networking in the background, the fact that the service may not run continuously, needing a wifi lock or to occasionally generate your own traffic to keep it up, etc. You may want to do a search for specifically Android solutions rather than trying to figure it out on your own. – Chris Stratton Aug 02 '14 at 12:50
  • Hi. My goal is create a locale network, but based on HTTP protocol. In my project, clients are local, and at most, there are 2 or 3 clients,not more. By running the service as a foreground, I think it can be run continuously.Is there any example to do this? – ebi Aug 02 '14 at 13:08

2 Answers2

2

As of 2021, I don't think the answers provided here give a straight forward solution. This is what worked for me:

  • you need a jar file with com.sun.net.httpserver... classes AND other classes that are used by the above
  • you need to tell Android Studio to look for those classes in that jar file in order to be able to import them in your java files in your app
  • you need to request <uses-permission android:name="android.permission.INTERNET" />

Procedure:

  • copy the jar file into your app's libs folder (in my case, c:\Android Projects\<Project Name>\app\libs). Where do you find such a file? In any java distribution, so in my case I simply used the rt.jar file from my Android Studio's jre\libs folder (in my case C:\Android Studio\jre\jre\lib\rt.jar). You may frown upon the fact that that is a 60 MB file, but the resulting apk was not significantly bigger than without the httpserver, so I assume the compiler only takes what it needs plus all dependencies.
  • in your Android Studio project, open the view in Project view (see image 1) switch to Project view
  • once you have copied the rt.jar file into app/libs, it should appear in your project view, if not, right click the app icon and click Reload from Disk (see image 2) Reload from Disk
  • then you right click the icon of your new rt.jar file and select Add As Library (see image 3) Add As Library

I have tried stripping down the rt.jar file to something smaller, but even though my app could compile and run, the first instance where a method was called using any of the imported classes from com.sun.net.*, the app would crash (as in CRASH, not raise an exception). Thus you better include the entire rt.jar file. The example below taken from Simple HTTP server in Java using only Java SE API

Now you can import

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

and in your app's Activity class, create a simple http server the following way:

    HttpServer server;

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            System.out.println(t.toString());
            String response = "This is the response";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        (new AsyncTask<String, Void, String>() {
            @Override
            protected String doInBackground(String... params) {
                try {
                    server = HttpServer.create(new InetSocketAddress(8001), 0);
                    server.createContext("/ho", new MyHandler());
                    server.setExecutor(null);
                    server.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }).execute("");
    }

mxl
  • 637
  • 7
  • 9
1

It should be available with JDK from 1.6 onwards. Otherwise, you can add it your build path separately. Refer below link:

You can download it from http://download.java.net/maven/2/com/sun/net/httpserver/http/20070405/http-20070405.jar

Arnab Nandy
  • 6,472
  • 5
  • 44
  • 50
  • As the question does involve targeting a JVM, but rather an Android device, ordinary jar's will not work. If the package is not included in the Android system, it would have to be re-built from source, and any missing dependencies supplied or replaced with supported alternatives. – Chris Stratton Aug 02 '14 at 12:37
  • ok i didn't know that ordinary jar will not work, but is there any way to re-built them from source to make it useful for android devices. – Arnab Nandy Aug 02 '14 at 12:46
  • Hi Chris.Thanks for your answer.How can I get related source file(s) and rebuild them? – ebi Aug 02 '14 at 12:47