做了一个这样的功能:
Android 调用AJAX进行登录
遇到的问题有:

跨域访问题:
*出现的错误信息是:Origin null is not allowed by Access-Control-Allow-Origin.
原因是:XMLHttpRequest2 进行跨域访问时需要服务器许可,不是任何域都接受跨域请求的,
网上有说是在HTML中加上

<meta http-equiv="Access-Control-Allow-Origin" content="*">

或者是在ajax中把dataType: “json”改为dataType: “jsonp”,

第一种情况没有变化,第二种改为jsonp的话会变为
Console: Uncaught SyntaxError: Unexpected token :错误
如果是在远程服务器里ajax()请求外域服务器里的页面,即使通过服务器环境运行也会报跨域的错误,此时需要通过JSONP的形式!
什么是JSONP?
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
虽然可以解决这个跨越的问题,但是我返回的数据格式就不对了

类似跨越问题是需要服务器端进行配置的,APP端设置是不起作用。
主要的原因是WebKit和Chromium这两个内核
Android 4.4之后出现的Chromium,关于这两个内核的区别和各自的相关信息可参考 理解WebKit和Chromium
本案例整体思路:
Android用户的账号和密码均由EditText输入,点击Button 调用Ajax请求访问,将name和password传入,等Ajax请求完毕后,将信息回调给Android,同时把获得到的token存储到本地。
登录成功后,显示主题界面,主题界面需要token,然后在html加载的时候,把我们存储在APP中的token加载到JS中。
前言:
1.我使用的是腾讯TBS浏览器服务
2.官网腾讯TBS
环境配置步骤:(android studio 2.3)
1.导入jar包和jniLibs下的动态库文件(.so文件)
2.defaultConfig中添加如下信息:
ndk {
abiFilters "armeabi", "armeabi-v7a", "x86_64", 'armeabi-v8a', 'x86', "mips"
}

3.初始化在Application中

public class App extends Application {    private static App myApplaction;    public static  String ID = null;    public static  String TOKEN = null;    @Override    public void onCreate() {        super.onCreate();        myApplaction=this;        preinitX5WebCore();        //预加载x5内核        Intent intent = new Intent(this, AdvanceLoadX5Service.class);        startService(intent);    }    public static App getIntance(){        return myApplaction;    }    private void preinitX5WebCore() {        if (!QbSdk.isTbsCoreInited()) {            QbSdk.preInit(getApplicationContext(), null);// 设置X5初始化完成的回调接口        }    }    // x5 init service    public class AdvanceLoadX5Service extends Service {        @Nullable        @Override        public IBinder onBind(Intent intent) {            return null;        }        @Override        public void onCreate() {            super.onCreate();            initX5();        }        private void initX5() {            //  预加载X5内核            QbSdk.initX5Environment(getApplicationContext(), cb);        }        QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {            @Override            public void onViewInitFinished(boolean arg0) {                // TODO Auto-generated method stub                //初始化完成回调            }            @Override            public void onCoreInitFinished() {                // TODO Auto-generated method stub            }        };    }}

4.封装一个BaseWebAcitity(我封装的不完美,还在改进中)

/** * Created by adminZPH on 2017/4/24. */public class BaseWebViewActivty extends Activity{    private final String TAG="BaseWebViewActivty";    private View headview;    private WebView webView;    private String url;    @Override    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {        super.onCreate(savedInstanceState, persistentState);        getWindow().setFormat(PixelFormat.TRANSLUCENT);        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);    }    public void setHeadview(View headview){        this.headview=headview;//        setstatusbarcolor();    }    public void SetWebView(WebView webView,String url){        this.webView=webView;        this.url=url;        Setting();    }    public void ShowWebView(){        webView.loadUrl(url);        webView.setWebViewClient(new MyWebViewClient());        webView.setWebChromeClient(new MyWebChromeClient());    }    private void Setting(){        WebSettings settings = webView.getSettings();        settings.setSupportZoom(true);        settings.setJavaScriptEnabled(true);        settings.setJavaScriptCanOpenWindowsAutomatically(true);        settings.setBuiltInZoomControls(true);        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);        settings.setBuiltInZoomControls(false);        webView.setHorizontalScrollBarEnabled(false);        webView.setVerticalScrollBarEnabled(false);        /**         * 设置本地缓存策略         * */        webView.getSettings().setDomStorageEnabled(true);        webView.getSettings().setAppCacheMaxSize(1024*1024*8);        String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();        webView.getSettings().setAppCachePath(appCachePath);        webView.getSettings().setAllowFileAccess(true);        webView.getSettings().setAppCacheEnabled(true);        //下面方法去掉线条        IX5WebViewExtension ix5 = webView.getX5WebViewExtension();        if (null != ix5) {            ix5.setScrollBarFadingEnabled(false);        }    }    /**     * 自定义的MyWebViewClient     * */    public class MyWebViewClient extends com.tencent.smtt.sdk.WebViewClient{        @Override        public boolean shouldOverrideUrlLoading(WebView view, String url) {            // 返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器            view.loadUrl(url);            return true;        }        @Override        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {            // 重写此方法可以让webview处理https请求。            super.onReceivedSslError(view, handler, error);            handler.proceed();        }        @Override        public void onPageStarted(WebView view, String url, Bitmap favicon) {            // 在页面加载开始时调用。            super.onPageStarted(view, url, favicon);            Log.i(TAG,"onPageStarted");        }       @Override        public void onPageFinished(WebView view, String url) {            // 在页面加载结束时调用。            super.onPageFinished(view, url);            Log.i(TAG,"onPageFinished");            webView.setVisibility(View.VISIBLE);        }        @Override        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {            // 网络不通,加载失败            super.onReceivedError(view, errorCode, description, failingUrl);            view.loadData("网络连接失败,请稍后重试!", "text/html; charset=utf-8", "utf-8");        }        @Override        public void onLoadResource(WebView view, String url) {            // 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。            super.onLoadResource(view, url);        }    }    public class MyWebChromeClient extends com.tencent.smtt.sdk.WebChromeClient {        @Override        public void onProgressChanged(WebView view, int newProgress) {            if (newProgress == 100) {            } else {            }            super.onProgressChanged(view, newProgress);        }        @Override        public void onReceivedTitle(WebView view, String title) {            super.onReceivedTitle(view, title);        }    }    @Override    public void onBackPressed() {//        finish();        if (null!=webView&&webView.canGoBack()){            webView.goBack();//            return true;        }    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if (keyCode==KeyEvent.KEYCODE_BACK){            if (null!=webView&&webView.canGoBack()){                webView.goBack();                return true;            }            setResult(Activity.RESULT_OK);        }        return super.onKeyDown(keyCode, event);    }}

在Src/java目录下建立assets文件夹,写一个html文件如下:

<html><head>    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">    <title>登录title>    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />    <style type="text/css">        body {            padding-top: 40px;            padding-bottom: 40px;            background: none;        }        .form-signin {            max-width: 300px;            padding: 19px 29px 29px;            margin: 0 auto 20px;            background-color: #fff;            border: 1px solid #e5e5e5;            -webkit-border-radius: 5px;            -moz-border-radius: 5px;            border-radius: 5px;            -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);            -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);            box-shadow: 0 1px 2px rgba(0, 0, 0, .05);        }        .form-signin .form-signin-heading,        .form-signin .checkbox {            margin-bottom: 10px;        }        .form-signin input[type="text"],        .form-signin input[type="password"] {            font-size: 16px;            height: auto;            margin-bottom: 15px;            padding: 7px 9px;        }    style>head> <body>        <div class="container-fluid">            <div class="form-signin" style="text-align: center;">                <h2 class="form-signin-heading">登录h2>                <input type="text" id="username" name="username" class="input-block-level" placeholder="账号" style="width: 100%!important;">                <br/>                <input type="password" id="password" name="password" class="input-block-level" placeholder="密码" style="width: 100%!important;">                <p><button class="btn btn-large btn-success" id="login"  type="submit">登录button>p>            div>        div>    body><script type="text/javascript" src="js/jquery.min.js">script><script type="text/javascript">    function loginclick(username,password) {        console.log(username);        $.ajax({            url: "http://XXX.XXX.X.XX:8080/XXXX/XXXX.go?method=XXXXXX",            data: { "username": username, "password": password },            type: "post",            dataType: "json",            success: function (result) {                console.log(result.state)                if (result.state == "OK") {                    window.android.ShowMessage(result.msg);                }                if(result.state=="ERROR"){                    window.android.ShowMessage("1");                }            },            error: function () {                window.android.ShowMessage("0");            }        });    }script>html>

其中有一个function loginclick(),就是我们要调用的ajax方法,
对于Android和JS互调,需要实体类中方法做中间引领人,
这里我封装一个接口如下:

public interface BaseJsImp {    /**     * 显示一些提示信息的方法     * */    @JavascriptInterface    public void ShowMessage(String T);    /**     * Js调用Android的方法     * */    @JavascriptInterface    public void JsToAndroid(Object... T);    /**     * Android调用JS的方法     * */    @JavascriptInterface    public void AndroidToJs(Object... T);    /**     * Js调用调用android方法,带有返回值的     * */    @JavascriptInterface    public Object GetDateFromAndroid();    /**     * Js调用调用android方法,带有返回值的和参数的     * */    @JavascriptInterface    public Object GetDateFromAndroid(Object... T);}

接下来到了我们的登录功能中:
在xml文件中,edittext和button随便写
关键是加上

 <com.tencent.smtt.sdk.WebView        android:layout_width="0dp"        android:id="@+id/login_webview"        android:layout_height="0dp">    com.tencent.smtt.sdk.WebView>

在LoginActivity中(部分方法可能只有我有)
代码如下

public class LoginActivity extends BaseWebViewActivty implements View.OnClickListener {    private Button login;    private ImageView weixin,qq;    private MaterialEditText name,password;    private LoadingDialog loadingDialog;    private WebView webView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);        initHeadView();        //加载资源文件        SetWebView(webView,"file:///android_asset/static/login.html");        ShowWebView();        //初始化回传信息接口        webView.addJavascriptInterface(new LoginClass(), "android");    }    private void initHeadView() {        login= (Button) findViewById(R.id.login_btn);        name= (MaterialEditText) findViewById(R.id.login_username);        password= (MaterialEditText) findViewById(R.id.login_password);        weixin= (ImageView) findViewById(R.id.weixin_login);        qq= (ImageView) findViewById(R.id.qq_login);        login.setOnClickListener(this);        weixin.setOnClickListener(this);        qq.setOnClickListener(this);        webView= (WebView) findViewById(R.id.login_webview);        setstatusbarcolor();    }    @Override    public void onClick(View view) {        switch (view.getId()){            case R.id.login_btn:                if(name.getText().toString().equals("")){                    toast("账号不能为空");                    return;                }                if(password.getText().toString().equals("")){                    toast("密码不能为空");                    return;                }                Login(name.getText().toString(),password.getText().toString());                break;            case R.id.weixin_login:                break;            case R.id.qq_login:                break;        }    }    private void Login(String name,String psd) {        loadingDialog=new LoadingDialog(this,"登录中");        loadingDialog.show();        //把我们的信息传入JS中        webView.loadUrl("javascript:loginclick('"+name+"','"+psd+"')");    }    @Override    protected void onDestroy() {        super.onDestroy();    }    public class LoginClass implements BaseJsImp {        @Override        public void ShowMessage(String message) {            if(loadingDialog!=null){                if(loadingDialog.isShowing()){                    loadingDialog.dismiss();                }            }            if(message.equals("0") ||message.equals("1")) {                toast("登录失败!");                Log.i("TAG","登录失败");            }            else {                Log.i("TAG","登录成功"+message);                toast("登录成功!"+message);                String[] a = message.split(",");                App.ID=a[0];                App.TOKEN=a[1];                Intent intent=new Intent(LoginActivity.this,TestActivity.class);                intent.putExtra("url",message);                startActivity(intent);//                AddDB();            }        }        @Override        public void JsToAndroid(Object... T) {        }        @Override        public void AndroidToJs(Object... T) {        }        @Override        public Object GetDateFromAndroid() {            return null;        }        @Override        public Object GetDateFromAndroid(Object... T) {            return null;        }    }    @Override    public void onBackPressed() {        super.onBackPressed();        this.finish();    }    private void AddDB() {        User u=new User();        u.setLoginState(true);        u.setUsername(name.getText().toString());        u.setPassword(password.getText().toString());        DBUtil.initDataBase(u);        this.finish();    }}

上述实例中,可以看出JS和Android互调用法
Android中方法
webView.addJavascriptInterface(new LoginClass(), “android”);
Js中(JS将信息回传给ANdroid)
window.android.ShowMessage(result.msg);

接下来,如何在JS加载中拿到保存在Android中所需要的token呢?

一个html页面中需要很多js,每个js都可能是一个单独的文件,我们解决在不同JS中调一个Android中的数据时候的思路是:
在主HTML中设置全局变量,然后每一个js都调用这个,对于token的话就需要在初始化数据的时候再ajax请求中添加headers,然后把我们android中的保存token加载过去。
实例如下:
主html文件:
在head中:

<script>        var _access_tocken = window.android.GetDateFromAndroid();script>

如果我们是在一个新的Activity中加载的话,在新的Activity中需要
webView.addJavascriptInterface(new NewClass(), “android”);

NewClass继承我们的BaseJsImp,只要将重写的GetDateFromAndroid()返回我们所需的token
如下:

 @Override        public Object GetDateFromAndroid() {            if(App.TOKEN!=null)                return App.TOKEN;            else                return null;        }

然后在我们的主html中数据初始化的js中添加headers
如下

//自定义的方法function myDefultAction() {        $.ajax({        url: baseurl+"getAgenda",        headers: {                access_tocken: _access_tocken        },        //data :{"_date":_date,"title":password},        type: "post",        dataType: "json",        // async: false,

通过以上方式我们就可以将动态的添加token到js中

这片海
2017-04-26

更多相关文章

  1. Android百度地图(一):百度地图定位sdk 类方法参数、定位原理详细
  2. Android NFS文件系统挂载遇到的问题解决方法
  3. [置顶] Android入门系列一(Android学习方法)
  4. Android控件阴影效果的几种实现方法
  5. Android Init Language(安卓初始化语言)
  6. Android VideoView设置静音,Android 设置VideoView静音,Android
  7. ListView去掉分割线的几种方法
  8. SDK Platform Tools component is missing! Please use the SDK
  9. Android Market google play store帐号注册方法流程 及发布应用

随机推荐

  1. Android 之 Android目录
  2. 第3.3.1节 处理手势操作
  3. Android常见报错之 - Only the original
  4. Android脚本语言环境 SL4A
  5. 平安科技移动开发二队技术周报(第十三期)
  6. 2017年11月1日Android职位数据分析
  7. 史上最全的android studio 插件大全整理
  8. Android之ActionBar学习
  9. 在Android Studio中使用Wifi连接Android
  10. 安卓boot recovery解包打包