类型
Post
状态
Published
日期
Sep 8, 2022
文章链接
build-an-android-shell-using-webview-from-scratch
概览
折腾项目的时候,难免会玩到安卓,虽然我是web端的前端开发,而且多少会一点安卓原生,但是折腾起来太过麻烦,花费的精力和收益不成正比,于是还是决定自己手撸一个安卓外壳,内嵌webview,通过开发h5的方式达到开发安卓app的目的。
标签
Android
App
分类
技术分享
图标
密码
创建时间
Sep 8, 2022 06:17 PM
最近更新时间
Sep 8, 2022 06:27 PM
折腾项目的时候,难免会玩到安卓,虽然我是web端的前端开发,而且多少会一点安卓原生,但是折腾起来太过麻烦,花费的精力和收益不成正比,于是还是决定自己手撸一个安卓外壳,内嵌webview,通过开发h5的方式达到开发安卓app的目的。
安装安卓开发环境
下载并安装 android studio

新建项目

选择默认即可

设置新项目的必要配置
- Name:应用名
- Package Name:包名
- Save Location:项目保存路径
- Language:项目使用的编程语言
- Minimum SDK:最低兼容 SDK 版本

开发安卓程序
新建一个MWebView控件
新建文件
controls/MWebView.java
package com.jsmiao.webapp.controls; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.os.Build; import android.util.AttributeSet; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; public class MWebView extends WebView { private Activity mActivity; public MWebView(Context context) { super(context); init(); } public MWebView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 设置要选择图片的activity * * @param activity */ public void setActivity(Activity activity) { this.mActivity = activity; } @SuppressLint("SetJavaScriptEnabled") private void init() { WebSettings webSettings = getSettings(); // 设置 // 开启JavaScript支持 webSettings.setJavaScriptEnabled(true); // 让Webivew支持<meta>标签的viewport属性 webSettings.setUseWideViewPort(true); // 是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false webSettings.setLoadWithOverviewMode(true); /** * 基于WebView导航的类型使用缓存:正常页面加载会加载缓存并按需判断内容是否需要重新验证。 * 如果是页面返回,页面内容不会重新加载,直接从缓存中恢复。setCacheMode允许客户端根据指定的模式来 * 使用缓存。 * LOAD_DEFAULT 默认加载方式 * LOAD_CACHE_ELSE_NETWORK 按网络情况使用缓存 * LOAD_NO_CACHE 不使用缓存 * LOAD_CACHE_ONLY 只使用缓存 */ webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); // 是否存储页面DOM结构,默认false。 webSettings.setDomStorageEnabled(true); // 是否允许访问WebView内部文件,默认true webSettings.setAllowFileAccess(true); // 是否允许获取WebView的内容URL ,可以让WebView访问ContentPrivider存储的内容。 默认true webSettings.setAllowContentAccess(true); // 设置页面的编码格式,默认UTF-8 webSettings.setDefaultTextEncodingName("utf-8"); // 是否允许运行在一个URL环境中的JavaScript访问来自其他URL环境的内容 webSettings.setAllowFileAccessFromFileURLs(false); // 是否允许运行在一个file schema URL环境下的JavaScript访问来自其他任何来源的内容,包括其他file schema URLs webSettings.setAllowUniversalAccessFromFileURLs(false); /** * Webview在安卓5.0之前默认允许其加载混合网络协议内容 * 在安卓5.0之后,默认不允许加载http与https混合内容,需要设置webview允许其加载混合网络协议内容 */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); //测试打开 WebView.setWebContentsDebuggingEnabled(true); } setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //判断url是否以http或https开头,是则不消费事件 if (url.startsWith("http:") || url.startsWith("https:")) { return false; } return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } }); setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); } @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); } }); } }

设置Layout布局
layout目录主要用于存放定义用户界面布局的 XML 文件。有些类似于web端的html,不过更为复杂。
修改
app/res/layout/activity_main.xml
文件,修改代码如下<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.jsmiao.webapp.controls.MWebView android:id="@+id/mWebView" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
看不到代码的,需要调整到Code

修改MainActivity文件
Activity 类是 Android 应用的关键组件,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分。
package com.jsmiao.webapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import com.jsmiao.webapp.controls.MWebView; public class MainActivity extends AppCompatActivity { private MWebView mWebView; // webView 控件 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 获取控件 mWebView = (MWebView) findViewById(R.id.mWebView); mWebView.setActivity(this); String url; // 设置url地址 url = "https://blog.jsmiao.com"; // 加载url mWebView.loadUrl(url); } }

添加联网权限
选择
app/minifests/AndroidMinifest.xml
文件,在 application
标签前添加一个 uses-permission
标签来声明应用的网络访问权限,最后保存。<!-- 访问网络的权限 --> <uses-permission android:name="android.permission.INTERNET" />

运行调试
连接手机,选择打开调试(也可以安装虚拟机)

不出意外的话,结果如下:

打包
选择打包

选择APK

新建一个

选择文件夹

配置密钥文件

然后输入这个jks和别名的一些相关信息,上方的商店密码和别名密码可以设置为一样的,这样便于记忆,只不过安全系数就降低了。

记住密码

选择release 点击finish 等待打包

打包好之后,将会在文件夹中看到你打包的app了

以上,我们想要的基本功能就已经完成了,以下功能可以根据需要进行拓展。
隐藏标题栏
在
themes.xml
中增加代码:<style name="Theme.Webapp.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style>

在
AndroidManifest.xml
文件中使用该主题
重启即可

设置状态栏
修改状态栏颜色
在
themes.xml
中增加代码:<style name="Theme.Webapp.NoActionBar"> ... <item name="android:statusBarColor">自己想要的颜色</item> </style>


隐藏状态栏
在
MainActivity
中 onCreate
方法内增加代码:// 设置为全屏(隐藏状态栏) getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
需要加在
setContentView
方法执行的前面
重新运行,状态栏就没有了,页面为全屏状态(刘海屏还是会有个黑条)

接管返回键
在
MainActivity
中 onCreate
方法内修改代码:private WebView webView = null; // 创建 WebView 实例时保存到 this.webView 中 /* * 重写onBackPressed函数 接管返回键 */ @Override public void onBackPressed() { if (this.webView.canGoBack()) { this.webView.goBack(); } else { super.onBackPressed(); } }
设置可http明文传输
从Android 9.0(API级别28)开始,默认情况下限制了明文流量的网络请求,对未加密流量不再信任,直接放弃请求,因此http的url均无法在webview中加载,https 不受影响。
在
AndroidManifest.xml
文件的 application
标签内,加入属性:android:usesCleartextTraffic="true"

- 作者:Jenson
- 链接:https://blog.jsmiao.com/article/build-an-android-shell-using-webview-from-scratch
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。