javaandroidhtmllocalhostnanohttpd

Using nanohttpd for server on localhost, how to serve the static HTML code in the whole directory?


I can't make nanohttpd work. It seems not be able to find the www directory in app's root.

My code is at https://github.com/tlkahn/neonx

My code at MainActivity.java:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        mWebView = findViewById(R.id.webkit);
        navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        webSettings.setDomStorageEnabled(true);
        mWebView.getSettings().setLoadsImagesAutomatically(true);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                return false;
            }
        });
        if (!haveNetworkConnection()) {
            new AlertDialog.Builder(this)
                .setTitle("You are not connected to internet.")
                .setMessage("Are you sure you want to exit?")
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finishAffinity();
                        System.exit(0);
                    }
                }).setNegativeButton("No", null).show();
        }
        startLocalServer(3000, "www", true, true );
    }

  public void startLocalServer(int port, String root, Boolean localhost, Boolean keepAlive) {
      try {
          File www_root = new File(root);
          server = new WebServer("localhost", port, www_root.getAbsoluteFile());
          server.start();
          printIp();
      } catch (IOException e) {
          e.printStackTrace();
      }
  }

When I tried to visit localhost:3000, I got the error: given path is not a directory. The error seems to come from this line: https://git.io/fjS3f

I guess the way I initialize the rootDir is wrong (this line: https://git.io/fjS3v). But how can I make this work? I mean to serve the whole directory, which means all CSS/JS/hypyerlinks should work, once nanohttpd starts serving...


Solution

  • Output: enter image description here

    LogCat:

    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: -------Assets List-----
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: asset-manifest.json
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: favicon.ico
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: index.html
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: manifest.json
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: precache-manifest.81af63d07b6dd6ae8e331187c522b020.js
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: service-worker.js
    2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: static
    2019-08-05 15:21:53.842 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www
    2019-08-05 15:21:53.865 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static
    2019-08-05 15:21:53.867 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static/css targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static/css
    2019-08-05 15:21:53.922 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static/js targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static/js
    2019-08-05 15:21:54.352 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static/media targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static/media
    2019-08-05 15:21:54.526 10650-10650/com.neonxorg.neonx E/MainActivity: -------Root File List-----
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/precache-manifest.81af63d07b6dd6ae8e331187c522b020.js
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/service-worker.js
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/favicon.ico
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/manifest.json
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/asset-manifest.json
    2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/index.html
    2019-08-05 15:21:54.704 10650-10650/com.neonxorg.neonx E/MainActivity: Connected : Please access! http://192.168.1.2:3000 From a web browser
    

    Code:

    public final String TAG = getClass().getSimpleName();
    public void startLocalServer(int port, String root, Boolean localhost, Boolean keepAlive) {
            try {
                String[] filePathList = (getAssets().list("www"));
                Log.e(TAG,"-------Assets List-----");
                for (String s : filePathList) {
                    Log.e(TAG, s);
                }
                File externalCache = getExternalCacheDir();
                if (externalCache != null) {
                    String path = externalCache.getAbsolutePath() + "/" + root;
                    copyFolderFromAssets(getApplicationContext(), "www", path);
                    File www_root = new File(path);
                    Log.e(TAG,"-------Root File List-----");
                    for (File f : www_root.listFiles()) {
                        Log.e("File ", f.getAbsolutePath());
                    }
                    server = new WebServer("localhost", port, www_root.getCanonicalFile());
                    server.start();
                    printIp();
                }
    
            } catch (IOException e) {
                Log.e(TAG, Log.getStackTraceString(e));
            }
        }
    
        public void copyFolderFromAssets(Context context, String rootDirFullPath, String targetDirFullPath) {
            Log.e(TAG,"copyFolderFromAssets " + "rootDirFullPath-" + rootDirFullPath + " targetDirFullPath-" + targetDirFullPath);
            File file = new File(targetDirFullPath);
            if (!file.exists()) {
                new File(targetDirFullPath).mkdirs();
            }
            try {
                String[] listFiles = context.getAssets().list(rootDirFullPath);// 遍历该目录下的文件和文件夹
                for (String string : listFiles) {// 看起子目录是文件还是文件夹,这里只好用.做区分了
                    if (isFileByName(string)) {// 文件
                        copyFileFromAssets(context, rootDirFullPath + "/" + string, targetDirFullPath + "/" + string);
                    } else {// 文件夹
                        String childRootDirFullPath = rootDirFullPath + "/" + string;
                        String childTargetDirFullPath = targetDirFullPath + "/" + string;
                        new File(childTargetDirFullPath).mkdirs();
                        copyFolderFromAssets(context, childRootDirFullPath, childTargetDirFullPath);
                    }
                }
            } catch (IOException e) {
                Log.e(TAG, Log.getStackTraceString(e));
            }
        }
    
    
        public void copyFileFromAssets(Context context, String assetsFilePath, String targetFileFullPath) {
            InputStream assestsFileInputStream;
            try {
                assestsFileInputStream = context.getAssets().open(assetsFilePath);
                FileOutputStream fOS = new FileOutputStream(new File(targetFileFullPath));
                int length = -1;
                byte[] buf = new byte[1024];
                while ((length = assestsFileInputStream.read(buf)) != -1) {
                    fOS.write(buf, 0, length);
                }
                fOS.flush();
            } catch (IOException e) {
                Log.e(TAG, Log.getStackTraceString(e));
            }
        }
    
        private boolean isFileByName(String str) {
            return str.contains(".");
        }
    
        private void printIp() {
            WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
            int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
            final String formatedIpAddress = String.format("%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
                    (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
            Log.e(TAG,"Connected : " + "Please access! http://" + formatedIpAddress + ":" + server.getListeningPort() + " From a web browser");
        }
    

    given path is not a directory.

    When nanphttpd is not able to locate the data then it gives this error.

    Why You are not getting the actual error

    In the catch block of copyFolderFromAssets and copyFileFromAssets you are using e.printStackTrace() which may not be showing on your LogCat due to Show only selected application filter

    enter image description here

    In order to print the errors, you need to use the following:

    Log.e(TAG, Log.getStackTraceString(e));
    

    I replaced all of your System.out and e.printStackTrace with Log.e statements. Most likely the app wasn't able to copy contents from www directory to target directory. I changed target directory to cache directory and it worked on my device. (see below):

    File externalCache = getExternalCacheDir();
    if (externalCache != null) {
        String path = externalCache.getAbsolutePath() + "/" + root;
        File www_root = new File(path);
        copyFolderFromAssets(getApplicationContext(), "www", path);
        Log.e(TAG,"-------Root File List-----");
        for (File f : www_root.listFiles()) {
            Log.e("File ", f.getAbsolutePath());
        }
        server = new WebServer("localhost", port, www_root.getCanonicalFile());
        server.start();
        printIp();
    }
    

    Sidenote: