最近在研究c++与Javascript的交互,有朋友问我安卓怎样与Javascript交互,今天找到一个之前写的小demo,实现的是安卓webview里面的Javascript和原生安卓进行交互。实现了安卓与Javascript交互,就可以用html+js+css在webview实现主要界面,Java只负责一些js不好实现的功能比如文件操作,数据库操作,摄像头操作等硬件操作。
首先要在工程的AndroidManifest.xml文件申请所需权限,比如摄像头,gps定位,访问存储卡等,代码大体如下。
然后就是写一些方法供Javascript调用,下面举几个例子
package com.jspp.sdxjwkq.js;
import android.app.Service;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.location.Location;
import android.location.LocationManager;
import android.os.Vibrator;
import android.support.v4.content.ContextCompat;
import android.webkit.JavascriptInterface;
import android.widget.Toast;
import java.util.List;
public class Utils {
private Camera camera;//照相机句柄
@JavascriptInterface
public boolean vibrate(int time){
Vibrator vibrator=(Vibrator) baseApplication.getContext().getSystemService(Service.VIBRATOR_SERVICE);
vibrator.vibrate(new long[]{0,time},-1);
return true;
}
@JavascriptInterface
public boolean openFlashlight(){
try{
camera= Camera.open();
if(camera!=null){
camera.startPreview();
Camera.Parameters parameters=camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
return true;
}
return false;
}catch (Exception e){
return false;
}
}
@JavascriptInterface
public boolean closeFlashlight(){
if(camera!=null){
camera.getParameters().setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(camera.getParameters());
camera.stopPreview();
camera.release();
camera=null;
return true;
}else{
return false;
}
}
@JavascriptInterface
public String getPosition(){
LocationManager locationManager=(LocationManager) baseApplication.getContext().getSystemService(Context.LOCATION_SERVICE);
//获取可用的位置提供器
String locationProvider;
List providers=locationManager.getProviders(true);
if(providers.contains(locationManager.GPS_PROVIDER)){
locationProvider=locationManager.GPS_PROVIDER;
}else if(providers.contains(locationManager.NETWORK_PROVIDER)){
locationProvider=locationManager.NETWORK_PROVIDER;
}else{
return "找不到地理位置获取设备";
}
if (ContextCompat.checkSelfPermission(baseApplication.getContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(baseApplication.getContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
Location location=locationManager.getLastKnownLocation(locationProvider);
if(location!=null){
return "{longitude:"+location.getLongitude()+",latitude"+location.getLatitude()+"}";
}else{
return "获取地理位置失败";
}
}else {
return "没有权限获取该设备地理位置";
}
}
@JavascriptInterface
public void toast(String msg){
Toast.makeText(baseApplication.getContext(),msg,Toast.LENGTH_LONG).show();
}
}
package com.jspp.sdxjwkq.js;
import android.webkit.JavascriptInterface;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
public class FileSystem {
public String DirRoot="/mnt/sdcard";//文件系统的根
@JavascriptInterface
public boolean createDirByUrl(String url){
File file=new File(this.DirRoot+url);
if(!file.exists()){
file.mkdirs();
return true;
}else{
return false;
}
}
@JavascriptInterface
public boolean fileExists(String url){
File file=new File(this.DirRoot+url);
return file.exists();
}
@JavascriptInterface
public String getFileListByUrl(String url){
try{
JSonArray jsonArray=new JSonArray();
File file=new File(this.DirRoot+url);
File[] subFile=file.listFiles();
for(int i=0;i
可以看到每一个类前面都要引入android.webkit.JavascriptInterface这个包,还有就是方法都要是public的,前面标注上@JavascriptInterface,声明为Javascript接口。
最后就是在相应的webview控件里面暴露这些接口啦,例如下面代码
package com.jspp.sdxjwkq.js;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class AppFragment extends Fragment {
private static WebView webView;
@Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
webView=getView().findViewById(R.id.webView1);
//新窗口使用webview
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view,String url){
view.loadUrl(url);
return true;
}
});
webView.getSettings().setJavascriptEnabled(true);//支持javascript
//javascript接口映射
webView.addJavascriptInterface(new Utils(), "Utils");
webView.addJavascriptInterface(new Sql(), "Sql");
webView.loadUrl("file:///mnt/sdcard/jspp/system/appList.html");
}
public static boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
webView.goBack();
return false;
}
return true;
}
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private onFragmentInteractionListener mListener;
public AppFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static AppFragment newInstance(String param1, String param2) {
AppFragment fragment = new AppFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_app, container, false);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
//用于页面间通信
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
// throw new RuntimeException(context.toString()
// + " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface onFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
//javascript接口映射
webView.addJavascriptInterface(new Utils(), "Utils");
webView.addJavascriptInterface(new Sql(), "Sql");
webView.loadUrl("file:///mnt/sdcard/jspp/system/appList.html");
这几句就是添加了Javascript接口映射,直接把实例化对象映射出去,
然后就是在js文件里使用了,比如想要手机振动一秒就可以在js里面直接写Utils.vibrate(1000);
针对js传参比较灵活的情况,java实现的时候可以对方法进行重载。
下面就是之前测试的效果
界面是用的原生的FragmentPager控件,中间白色部分是webview载入的本地网页。
可以看到在AndroidManifest.xml文件申请的那些权限,
因为应用本身没有多少图片等资源,所以打包之后也非常小巧。



