【手把手】带你撸一个安卓壳子

编程入门 行业动态 更新时间:2024-10-25 07:17:41

【手把手】带你撸一个安卓<a href=https://www.elefans.com/category/jswz/34/1676855.html style=壳子"/>

【手把手】带你撸一个安卓壳子

web前端的小伙伴们大家好,说起APP混合开发,大家首先想到的可能就是类似Cordova的库,可以让我们不写一行安卓代码,就轻松地实现原生APP的一些常用功能,但是对于一些特别的"需求"我们就无能为力了。所以为了提高我们的知识储备,我觉得还是有必要学习一波安卓的知识的。下面就由我带着大家手把手撸一个安卓的壳子出来,由于本人也是第一次写安卓的东西,难免会有些不对的地方,希望各路大神见怪莫怪。

1、下载Android Studio

官网下载地址,开发安卓貌似就只有这一个编辑器可用了,这个IDE风格和webStorm的风格一模一样,应该是一家公司的产品,这个没有深究过。安装过程在此就不详细说明了,有需要的可以自行百度。

2、创建一个新项目

打开IDE,点击 Start a new Android Studio project 创建一个新项目 

填写下面的信息(APP名称和域名建议和我填写一样,这样下面就不用改了^_^),点击next

选择APP支持的安卓最低版本,点击next

然后选择一个空白页,点击next

这里直接默认,最后点击 Finish

3、启动项目

至此,我的第一个APP已经创建完成,怎么运行它呢?有两种运行方式,一种是模拟器、一种真机。我建议使用真机,模拟器可能会出现一些意想不到的问题。

选择运行模式

第一个代表模拟器,第二个是真机,这里我们选择真机 USB Device,点击OK

接下来把我们的手机通过USB连接电脑,注意手机要打开 USB调试 ,简单说一下手机怎么打开 USB调试,以华为畅玩9为例,首先我们要打开手机的开发者模式,依次点击 设置>系统>关于手机>连续点击版本号(考验手速的时候到了!)   直到出现 "打开手机开发者模式"字样的提示,然后我们再点击 设置>系统>开发者选项>USB调试开关打开。

然后点击下面的绿色三角,运行程序,开始运行的时候手机上可能会弹出来一次 允许调试的授权框 ,我们点击允许。

大功告成!我们可以看到APP已经成功安装到手机上了

4、修改APP名称和图标

我们可以看到默认的APP图标和名称,作为一名优秀的前端开发,简直不能忍

修改图标:选择 File>New>Image Asset

Name的值不要改,Asset Type 选择 Image,path选择我们的图标路径,再通过 Resize 调整图片到合适大小,点击next。

我们看到了很多红色,不用鸟他,直接Finish

修改名称:打开 app>res>values>strings.xml  修改其中的 app_name 的值

修改完毕,我们再重新运行一下程序,哈哈,非常完美!

5、创建 webView,并去掉标题栏

既然是混合开发,webview是必须的,理论上我们的Android架子只需要一个页面放置webview即可。
首先我们要允许webview联网,打开 app>manifests>AndroidManifest.xml,在 application 上面添加一行:

<uses-permission android:name="android.permission.INTERNET" />

打开  app>res>layout>activity_main.xml 把默认的 TextView 控件删掉,加上webview控件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android=""xmlns:app=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><WebView  xmlns:android=""android:id="@+id/webview"android:layout_width="fill_parent"android:layout_height="fill_parent"/></android.support.constraint.ConstraintLayout>

我们发现还有一个默认的标题,这个也是不需要的,打开 app>manifests>AndroidManifest.xml,找到android:theme="@style/AppTheme"  改成下面的

android:theme="@style/Theme.AppCompat.Light.NoActionBar"

再次运行一下,标题栏没有了,但是白屏,那是因为我们还没有给webview链接。

6、webview的一些基本配置

*设置链接:

我们修改 MainActivity.java 文件中的MainActivity类,如下,(如果某个单词出现红色,说明没有引入包,把鼠标定位到红色单词上,按住 Alt + Enter 按照提示引入相应的包即可,之后不再重复说明此问题。)
myWebView.loadUrl( "/" ); 这行就是webview要加载的地址,我这里放的是一个服务器的地址,当然也可以放本地的,本地怎么放得这里就不做说明了。

public class MainActivity extends AppCompatActivity {private WebView myWebView = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate( savedInstanceState );setContentView( R.layout.activity_main );myWebView = (WebView) findViewById( R.id.webview );WebSettings webSettings = myWebView.getSettings();myWebView.loadUrl( "/" );}
}

服务器上对应的HTML文件如下:js相信大家都看的懂,就不解释了。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Carson</title>  <script>function callAndroid(){document.getElementById("output").innerHTML="欢迎来到单身狗联盟";}</script></head><body><button type="button" id="button1" onclick="callAndroid()">test</button><div id="output"></div></body>
</html>

*启用JS:

我们重新运行APP,当点击按钮之后并没有出现文字,这是因为webview默认是禁用JS的,在 MainActivity.java 中
WebSettings webSettings = myWebView.getSettings(); 后面加一句

webSettings.setJavaScriptEnabled( true );

重新运行APP,一切正常。

*让所有的超链接都在webview中打开:

我们再HTML文件中加入一个超链接

<a href=''>点击去百度</a>

重新运行APP,当我们点击 去百度 之后就会提示我们用默认浏览器打开这个网址,

对于混合开发APP,这样肯定是不行的,我们要让所有的链接都在webview中打开,在 MainActivity.java 中
webSettings.setJavaScriptEnabled( true ); 后面上如下内容

myWebView.setWebViewClient(new WebViewClient() {public boolean shouldOverrideUrlLoading(WebView view, String url) {return false;}
});

*允许webview拨打电话:

前端的小伙伴们都知道,给一个a标签的href属性设置为 tel:18538328225 ,在微信中,点击这个标签就可以调起手机通讯录,便于快捷拨号,那我们在我们的APP中试一下。结果却很尴尬。居然毫无反应,不能忍,改!修改 setWebViewClient() 方法如下:

myWebView.setWebViewClient(new WebViewClient() {public boolean shouldOverrideUrlLoading(WebView view, String url) {if (url.startsWith("tel:")) {Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));startActivity(intent);return true;}return false;}
});

*开启Storage:

sessionStorage和localStorage在很多项目里都会用到,特别是移动端,webview默认是不允许js访问的需要我们手动开启
在 setWebViewClient() 方法下面加上下面内容

webSettings.setDomStorageEnabled( true );
webSettings.setAppCacheMaxSize( 1024 * 1024 * 8 );
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webSettings.setAppCachePath( appCachePath );
webSettings.setAllowFileAccess( true );
webSettings.setAppCacheEnabled( true );

*返回键返回webview的历史记录:

当我们点击 去百度 就在本页面就打开了百度的链接,但当我们点击手机的物理返回键后,并没有返回我们的首页,而是直接退出了程序。这个也需要我们去做处理,在 onCreate() 的后面添加

public boolean
onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {myWebView.goBack();//返回上个页面return true;}return super.onKeyDown(keyCode, event);//退出H5界面
}

7、允许 input type:file 选择文件

这一块的内容还是比较多,也不是必须要开启的功能,所以单独拿出来说,在上传图片的时候,我们会用input标签 type=file 就能实现选择文件,并上传的功能,同样的,这也需要webview提供支持,在 private WebView myWebView = null; 后面加上  

private ValueCallback<Uri[]> uploadMessageAboveL;

然后在  setWebViewClient() 后面添加

webSettings.setAllowFileAccess(true);
myWebView.setWebChromeClient( new WebChromeClient(){public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams ) {if (uploadMessageAboveL != null) {uploadMessageAboveL.onReceiveValue(null);uploadMessageAboveL = null;}uploadMessageAboveL = filePathCallback;Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("image/*");startActivityForResult( Intent.createChooser(i, "Image Chooser"), 2);return true;}
});

最后在 onKeyDown() 后面加上

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult( requestCode, resultCode, data );if (requestCode == 2) {if (null == uploadMessageAboveL) return;Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();if (uploadMessageAboveL != null) {onActivityResultAboveL(requestCode, resultCode, data);}}
}//webview可以选择文件
private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");if (requestCode != 2 || uploadMessageAboveL == null) {return;}Uri[] results = null;if (resultCode == Activity.RESULT_OK) {if (data == null) {} else {String dataString = data.getDataString();ClipData clipData = data.getClipData();if (clipData != null) {results = new Uri[clipData.getItemCount()];for (int i = 0; i < clipData.getItemCount(); i++) {ClipData.Item item = clipData.getItemAt(i);results[i] = item.getUri();}}if (dataString != null) {results = new Uri[]{Uri.parse(dataString)};}}}uploadMessageAboveL.onReceiveValue(results);uploadMessageAboveL = null;return;
}

完美收工!至此一个完整的 webview 已经完成。谢谢阅读!

...

...

...

...

...

陈大海:你这个也太low了,还不如去用cordova,根本不用自己配置!
 

em....,看来只好放大招了!

8、JS 和 Android 实现交互

js和android实现交互有很多种方式,这里我选择了最简单的一种,以供大家快速上手。
首先我们把 Android 的类对象(AndroidtoJs)和JS(test)的对象建立映射关系,在 myWebView.loadUrl() 上面加一行

myWebView.addJavascriptInterface( new AndroidtoJs(), "test" );

然后在 onKeyDown()  下面添加与JS映射的类并添加一个hello方法

public class AndroidtoJs extends Object {@JavascriptInterfacepublic void hello(String msg) {final String content = msg;myWebView.post( new Runnable() {@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overridepublic void run() {myWebView.evaluateJavascript( "javascript:test.helloFn('hello,"+content+"')", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String value) { }} );}} );}
}

编辑我们的JS文件

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Carson</title><script>localStorage.setItem("text", "欢迎来到单身狗联盟");function callAndroid() {document.getElementById("output").innerHTML = localStorage.getItem("text");}function sayHello() {test.hello(document.getElementById("name").value);}test.helloFn = function (text) {document.getElementById("output").innerHTML = text;}</script>
</head>
<body><button type="button" id="button1" onclick="callAndroid()">test</button><div id="output"></div><a href=''>点击去百度</a><a href='tel:18668168404'>打电话</a><input type="file"><input id="name" type="text"><button onclick="sayHello()">say</button>
</body>
</html>

效果如下:

简单解释一下,因为 JS的 test 对象和Android的 AndroidtoJs 类进行了映射关系,所以当我用 js  调用 test 的 hello 方法,就相当于android 的 AndroidtoJs 去调用 hello 方法一样,反过来也是一样的。
既然js和android已经实现了交互,那么我们就来搞一波事情吧。

9、获取当前的实时GPS位置

首先我们定义一个方法,实现和JS的交互,在 AndroidtoJs 类里添加

//获取当前地理位置
@JavascriptInterface
public void getPosition(String msg) {showGPSContacts();
}

然后我们在 AndroidManifest.xml 文件中加上权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

最后在 MainActivity.java 文件中的 onActivityResult() 方法后面加上

//APP授权的回调
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(requestCode == 100){if (grantResults[0] == PERMISSION_GRANTED && grantResults.length > 0) {getLocation();} else {showGPSContacts();}}
}//获取地理位置
LocationManager lm;
Boolean positionNum=false;
public void showGPSContacts() {lm = (LocationManager) MainActivity.this.getSystemService(MainActivity.this.LOCATION_SERVICE);boolean ok = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);if (ok) {if (Build.VERSION.SDK_INT >= 23) {if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) {  // 没有权限,申请权限。ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE}, 100);} else {getLocation();}} else {getLocation();}} else {Intent intent = new Intent();intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);startActivityForResult(intent, 1315);}
}
private void getLocation() {LocationManager locationManager;String serviceName = Context.LOCATION_SERVICE;locationManager = (LocationManager) this.getSystemService(serviceName);Criteria criteria = new Criteria();criteria.setAccuracy(Criteria.ACCURACY_FINE);criteria.setAltitudeRequired(false);criteria.setBearingRequired(false);criteria.setCostAllowed(true);criteria.setPowerRequirement(Criteria.POWER_LOW);String provider = locationManager.getBestProvider(criteria, true);if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PERMISSION_GRANTED) { return; }Location location = locationManager.getLastKnownLocation(provider); // 通过GPS获取位置updateLocation(location);if(!positionNum){positionNum=true;lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 8, new LocationListener() {@Overridepublic void onLocationChanged(Location location) {updateLocation(location);}@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {}@SuppressLint("MissingPermission")@Overridepublic void onProviderEnabled(String provider) {updateLocation(lm.getLastKnownLocation(provider));}@Overridepublic void onProviderDisabled(String provider) {updateLocation(null);}});}
}
private void updateLocation(Location location) {if (location != null) {final double latitude = location.getLatitude();final double longitude = location.getLongitude();System.out.println(latitude+":"+longitude);myWebView.post( new Runnable() {@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overridepublic void run() {myWebView.evaluateJavascript( "javascript:test.getPositionFn('" + latitude+"','"+longitude+ "')", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String value) { }} );}} );} else {System.out.println("无法获取到位置信息");}
}

修改JS文件

test.getPosition('');
test.getPositionFn=function(lat,lng){document.getElementById("output").innerHTML = "lat:"+lat+",lng:"+lng;
}

重新运行APP查看效果

说明,首先会去判断手机有没有打开GPS,没有打开跳到手机系统打开GPS的页面,打开了GPS的,再去向用户请求获取地理位置的权限,等用户授权之后,每两秒查询一次用户的位置,如果有更新,就调用 js 的方法,把最新的经纬度传过去。

10、实现扫描二维码

这里我们使用一个第三方的包来实现此功能

引入包文件,打开下面文件

修改  其中的 allprojects 如下

allprojects {repositories {google()jcenter()maven { url '' }}
}

 打开下面文件

在 dependencies 中加入

implementation 'com.github.yuzhiqiang1993:zxing:2.2.1'

注意修改这两个文件之后窗口的顶部会出现如下提示,需要我们点击安装

然后我们在 AndroidManifest.xml 文件中加上权限

<uses-permission android:name="android.permission.CAMERA" />

 AndroidtoJs 类里定义一个和JS交互的方法

//启动扫描二维码
@JavascriptInterface
public void scanQRCode(String msg) {if (ContextCompat.checkSelfPermission( MainActivity.this, android.Manifest.permission.CAMERA ) != PERMISSION_GRANTED) {ActivityCompat.requestPermissions( MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1 );} else {Intent intent = new Intent( MainActivity.this, CaptureActivity.class );startActivityForResult( intent, 111 );}
}

在 onRequestPermissionsResult() 中加一个打开摄像头的授权方法

//APP授权的回调
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(requestCode == 100){if (grantResults[0] == PERMISSION_GRANTED && grantResults.length > 0) {getLocation();} else {showGPSContacts();}}else if(requestCode == 1){if(grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED){Intent intent = new Intent( MainActivity.this, CaptureActivity.class );startActivityForResult( intent, 111 );}}
}

最后在 onActivityResult() 方法里加上扫描二维码的结果

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult( requestCode, resultCode, data );if (requestCode == 2) {if (null == uploadMessageAboveL) return;Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();if (uploadMessageAboveL != null) {onActivityResultAboveL(requestCode, resultCode, data);}}else if (requestCode == 111 && resultCode == RESULT_OK) {if (data != null) {final String content = data.getStringExtra( Constant.CODED_CONTENT );myWebView.post( new Runnable() {@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overridepublic void run() {myWebView.evaluateJavascript( "javascript:test.scanQRCodeFn('" + content + "')", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String value) { }} );}} );}}
}

在修改一下JS的调用

function qrCode(){test.scanQRCode('');
}
test.scanQRCodeFn=function(text){document.getElementById("qrCode").innerHTML = "扫描二维码的结果是:"+text;
}

最后再重新运行一下

已经连续奋战3个小时了,今天就到这里了,存个档,有需要的朋友可以点这里下载全部代码

更多推荐

【手把手】带你撸一个安卓壳子

本文发布于:2024-02-10 19:10:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1676854.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:壳子   手把手   带你

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!