Android基于NanoHTTPD搭建本地Web服务器遇问题,求可用示例
在Android上搭建可访问本地index.html的Web服务器(完整可运行示例)
我懂你折腾了好几种方法都跑不起来的挫败感——Android环境下的Web服务器确实和普通Java项目不一样,比如不能在主线程启动、文件访问权限、网络配置这些坑都容易踩。下面给你一个基于NanoHTTPD的完整可运行方案,亲测能正常启动并加载本地assets里的index.html:
步骤1:添加依赖
在你的Module级别的build.gradle文件里,添加NanoHTTPD的依赖:
dependencies { // 其他依赖... implementation 'org.nanohttpd:nanohttpd:2.3.1' }
步骤2:配置权限和网络
在AndroidManifest.xml里添加必要的权限,同时允许明文HTTP请求(Android 9+默认禁止):
<uses-permission android:name="android.permission.INTERNET" /> <application // 其他属性... android:usesCleartextTraffic="true"> // Activity声明... </application>
步骤3:编写Web服务器类
创建一个继承自NanoHTTPD的类,负责处理请求并从assets读取静态文件:
import android.content.Context; import org.nanohttpd.NanoHTTPD; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; public class LocalWebServer extends NanoHTTPD { private Context mContext; public LocalWebServer(Context context, int port) throws IOException { super(port); this.mContext = context; } @Override public Response serve(IHTTPSession session) { // 默认访问根路径时返回index.html String requestUri = session.getUri(); if (requestUri.equals("/")) { requestUri = "/index.html"; } try { // 从assets文件夹读取目标文件 InputStream inputStream = mContext.getAssets().open(requestUri.substring(1)); byte[] fileBytes = new byte[inputStream.available()]; inputStream.read(fileBytes); inputStream.close(); String fileContent = new String(fileBytes, StandardCharsets.UTF_8); // 根据文件后缀设置正确的Content-Type String mimeType = getMimeType(requestUri); return newFixedLengthResponse(Response.Status.OK, mimeType, fileContent); } catch (IOException e) { // 文件不存在时返回404 return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "404 页面未找到"); } } // 简单的MIME类型映射,可根据需要扩展 private String getMimeType(String uri) { if (uri.endsWith(".html") || uri.endsWith(".htm")) { return "text/html"; } else if (uri.endsWith(".css")) { return "text/css"; } else if (uri.endsWith(".js")) { return "application/javascript"; } else if (uri.endsWith(".png")) { return "image/png"; } else if (uri.endsWith(".jpg") || uri.endsWith(".jpeg")) { return "image/jpeg"; } return "text/plain"; } }
步骤4:在Activity中启动服务器
注意不能在Android主线程启动服务器,所以要放在子线程里执行:
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private LocalWebServer webServer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 启动服务器的操作放在子线程 new Thread(() -> { try { // 监听8080端口 webServer = new LocalWebServer(MainActivity.this, 8080); webServer.start(); // 回到主线程显示提示 runOnUiThread(() -> Toast.makeText(MainActivity.this, "服务器启动成功!访问地址:http://localhost:8080", Toast.LENGTH_LONG).show() ); } catch (IOException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(MainActivity.this, "服务器启动失败:" + e.getMessage(), Toast.LENGTH_LONG).show() ); } }).start(); } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时停止服务器 if (webServer != null) { webServer.stop(); } } }
步骤5:放置你的index.html
在项目的app/src/main/assets目录下(如果没有assets文件夹,手动创建一个),放入你的index.html文件,示例内容:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Android本地服务器测试</title> </head> <body> <h1 style="color: #2196F3;">🎉 成功访问本地页面!</h1> <p>这是从Android assets文件夹加载的静态HTML文件</p> </body> </html>
测试方法
- 模拟器:直接在浏览器输入
http://localhost:8080即可访问 - 真机:先查看手机的局域网IP(比如192.168.1.100),然后在同一网络的设备浏览器输入
http://192.168.1.100:8080
内容的提问来源于stack exchange,提问作者huby
相关产品推荐
相关产品推荐

