扫码登录的简单实现-移动App端

程序结构如下:

一、在app模块添加依赖

    //动态权限
    implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'
    //二维码扫描库
    implementation 'com.google.zxing:core:3.2.1'
    implementation 'cn.bingoogolapple:bga-qrcodecore:1.1.9@aar'
    implementation 'cn.bingoogolapple:bga-zxing:1.1.7@aar'
    //Rx库
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'io.reactivex:rxandroid:1.2.1'
    implementation 'io.reactivex:rxjava:1.3.8'
    //retrofit2
    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.6.0'

二、在清单AndroidManifest.xml中添加权限

    <!--网络访问-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--摄像头-->
    <uses-permission android:name="android.permission.CAMERA"/>
    <!--振动器-->
    <uses-permission android:name="android.permission.VIBRATE"/>

三、网络访问会有问题,需要在res下创建xml\network_security_config.xml文件

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
<!--允许开启http请求-->

然后在AndroidManifest.xml中的application节点下添加:

 

android:networkSecurityConfig="@xml/network_security_config"

四、主界面布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <LinearLayout
        android:id="@+id/ll_user"
        android:layout_marginTop="200dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="50dp"
            android:layout_marginRight="50dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="用户名: " />

            <EditText
                android:id="@+id/et_username"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="50dp"
            android:layout_marginRight="50dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="密    码: " />

            <EditText
                android:id="@+id/et_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:layout_below="@id/ll_user"
        android:layout_centerHorizontal="true"
        android:orientation="horizontal">


        <Button
            android:id="@+id/btn_app_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="APP登录" />

        <Button
            android:id="@+id/btn_scan"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="二维码扫描" />
    </LinearLayout>

</RelativeLayout>

 

 主要就显示用户App端登录的界面,加一个跳转到二维码扫描的按钮。

五、主程序 MainActivity.java

package com.chris.base.scanloginapp;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private Button btnLogin, btnScan;
    private EditText etUsername,etPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        btnLogin = findViewById(R.id.btn_app_login);
        btnScan = findViewById(R.id.btn_scan);
        etUsername = findViewById(R.id.et_username);
        etPassword = findViewById(R.id.et_password);

        etUsername.setText("chenfabao");
        etPassword.setText("123456");

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                //SharedPreferences sp = getSharedPreferences("loginUser",MODE_PRIVATE);
                SharedPreferences.Editor edit = sp.edit();
                String username = etUsername.getText().toString().trim();
                edit.putString("username", username);
                String password = etPassword.getText().toString().trim();
                edit.putString("password", password);
                edit.commit();
                //setTitle(username + " : " + password);
                Toast.makeText(MainActivity.this, "APP登陆成功", Toast.LENGTH_SHORT).show();
            }
        });

        btnScan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this, ScanActivity.class));
            }
        });

    }
}

 

 六、扫码界面 activity_scan.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ScanActivity">

    <cn.bingoogolapple.qrcode.zxing.ZXingView
        android:id="@+id/zxv_qrcode_scan"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:qrcv_borderSize="0dp"
        app:qrcv_cornerColor="#3F4259"
        app:qrcv_isShowDefaultScanLineDrawable="true"
        app:qrcv_isShowTipTextAsSingleLine="true"
        app:qrcv_isTipTextBelowRect="true"
        app:qrcv_maskColor="#80000000"
        app:qrcv_qrCodeTipText="将二维码放入框内,即可自动扫描"
        app:qrcv_rectWidth="240dp"
        app:qrcv_scanLineColor="#44DB5E"
        app:qrcv_tipTextColor="#FFFFFF"
        app:qrcv_tipTextSize="16sp" />

</RelativeLayout>

七、扫码登录逻辑 ScanActivity.java

package com.chris.base.scanloginapp;

import android.Manifest;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.tbruyelle.rxpermissions.RxPermissions;

import cn.bingoogolapple.qrcode.core.QRCodeView;
import cn.bingoogolapple.qrcode.zxing.ZXingView;
import rx.functions.Action1;

public class ScanActivity extends AppCompatActivity implements QRCodeView.Delegate {
    private ZXingView zXingView;
    private String username, password;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan);
        getUserInfo();
        initView();
    }

    private void getUserInfo() {
        //SharedPreferences sp = getSharedPreferences("loginUser",MODE_PRIVATE);
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        username = sp.getString("username", "unkown");
        password = sp.getString("password", "unkown");
        Toast.makeText(ScanActivity.this, username + " : " + password, Toast.LENGTH_LONG).show();
        setTitle(username + " : " + password);
    }

    private void initView() {
        zXingView = findViewById(R.id.zxv_qrcode_scan);
        zXingView.setDelegate(this);

        if (Build.VERSION.SDK_INT >= 23) {
            RxPermissions.getInstance(this)
                    .request(Manifest.permission.CAMERA)
                    .subscribe(new Action1<Boolean>() {
                        @Override
                        public void call(Boolean aBoolean) {
                            if (aBoolean) {
                                zXingView.startCamera();
                                zXingView.startSpotDelay(500);
                                Toast.makeText(ScanActivity.this, "6.0获取权限成功", Toast.LENGTH_SHORT).show();
                            } else {
                                Toast.makeText(ScanActivity.this, "权限被拒绝", Toast.LENGTH_SHORT).show();
                                finish();
                            }
                        }
                    });
        } else {
            Toast.makeText(ScanActivity.this, "权限被拒绝", Toast.LENGTH_SHORT).show();
            zXingView.startCamera();
            zXingView.startSpotDelay(500);
        }
    }

    @Override
    public void onScanQRCodeSuccess(final String result) {
        Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
        //振动器
        Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
        vibrator.vibrate(200);

        //发出请求
        HttpUtils.login(username, password, result, new LoginCallback<String>() {
            @Override
            public void success(String data) {
                Toast.makeText(ScanActivity.this, username + " : " + password + " : " + result, Toast.LENGTH_SHORT).show();
                finish();
            }

            @Override
            public void failed(String message, Throwable t) {
                Toast.makeText(ScanActivity.this, "发送失败", Toast.LENGTH_SHORT).show();
                finish();
            }
        });

        //zXingView.startSpot();//可以多次识别
    }

    @Override
    public void onScanQRCodeOpenCameraError() {
        Toast.makeText(this, "无法识别", Toast.LENGTH_SHORT).show();
    }


}

 

这里我使用的是retrofit2网络请求框架。用到以下三个文件:

1. 请求回调LoginCallback.java,用于在工具类中请求成功后,在activity中修改UI

package com.chris.base.scanloginapp;

/**
 * create by Chris Chan
 * create on 2019/10/2 16:46
 * use for :
 */
public interface LoginCallback<T> {
    void success(T data);

    void failed(String message, Throwable t);
}

2. retrofit2的请求接口LoginService.java

package com.chris.base.scanloginapp;

import java.util.Map;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.QueryMap;

/**
 * create by Chris Chan
 * create on 2019/10/2 16:45
 * use for :
 */
public interface LoginService {
    //登录
    @GET("api/user/login")
    Call<Boolean> login(@QueryMap Map<String, Object> map);
}

 3. 封装好进行http请求的工具类HttpUtils.java

package com.chris.base.scanloginapp;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * create by Chris Chan
 * create on 2019/10/2 16:44
 * use for :
 */
public class HttpUtils {
    public static void login(String username, String password, String code, final LoginCallback<String> callback) {
        String baseUrl = "http://192.168.0.100:7021/";
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(10L, TimeUnit.SECONDS)
                .readTimeout(10L, TimeUnit.SECONDS)
                .writeTimeout(10L, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(baseUrl)
                .build();
        LoginService loginService = retrofit.create(LoginService.class);
        Map<String, Object> paramMap = new HashMap<>(16);
        paramMap.put("username", username);
        paramMap.put("password", password);
        paramMap.put("code", code);
        Call<Boolean> call = loginService.login(paramMap);
        call.enqueue(new Callback<Boolean>() {
            @Override
            public void onResponse(Call<Boolean> call, Response<Boolean> response) {
                if (response.body()) {
                    callback.success("登陆成功");
                }
            }

            @Override
            public void onFailure(Call<Boolean> call, Throwable t) {
                callback.failed(t.getMessage(), t);
            }
        });
    }
}

八、需要再次说明的是,这里的登录分两种,一种是App自己的登陆,会获取到用户信息。在这里我们没有做这个实现,只需要输入用户名和密码就视同登陆了。不过用户名和密码必须要是服务端在内存中添加过的那四个,否则后面验证不会通过。第二种登录时帮助web端进行的扫码登录,会携带自己的重要识别信息和扫描的识别码去登录,不为自己,是为了web端。扫码之前必须app是登录的。

经测试,三个端之间逻辑通畅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值