增加二维码

This commit is contained in:
2023-05-26 16:06:45 +08:00
parent ba9a7688db
commit 8598e6f861
15 changed files with 563 additions and 43 deletions

View File

@@ -71,7 +71,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activity.MainActivity">
<activity android:name=".activity.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@@ -1,18 +0,0 @@
package com.uiuipad.find.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.uiuipad.find.R;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

View File

@@ -0,0 +1,17 @@
package com.uiuipad.find.activity.main;
import android.graphics.Bitmap;
import com.uiuipad.find.base.BasePresenter;
import com.uiuipad.find.base.BaseView;
public class MainAContact {
interface Presenter extends BasePresenter<MainView> {
/*获取二维码*/
void getQrCode();
}
public interface MainView extends BaseView {
void setQrCode(Bitmap bitmap);
}
}

View File

@@ -0,0 +1,56 @@
package com.uiuipad.find.activity.main;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import com.trello.rxlifecycle4.android.ActivityEvent;
import com.uiuipad.find.comm.CommonConfig;
import com.uiuipad.find.util.BitmapUtils;
import com.uiuipad.find.util.CXAESUtil;
import com.uiuipad.find.util.Utils;
import io.reactivex.rxjava3.subjects.BehaviorSubject;
/**
* @author jgy02
*/
public class MainAPresenter implements MainAContact.Presenter {
private static final String TAG = MainAPresenter.class.getSimpleName();
private MainAContact.MainView mView;
private Context mContext;
public MainAPresenter(Context context) {
this.mContext = context;
}
private BehaviorSubject<ActivityEvent> lifecycle;
public void setLifecycle(BehaviorSubject<ActivityEvent> lifecycle) {
this.lifecycle = lifecycle;
}
public BehaviorSubject<ActivityEvent> getLifecycle() {
return lifecycle;
}
@Override
public void attachView(MainAContact.MainView view) {
this.mView = view;
}
@Override
public void detachView() {
this.mView = null;
}
@Override
public void getQrCode() {
String encryptString = CXAESUtil.encrypt(CommonConfig.AES_KEY, Utils.getSerial());
Log.e("getQRCode", "setImageAndText: " + encryptString);
Bitmap bitmap = BitmapUtils.createQRImage(encryptString, 400, 400);
mView.setQrCode(bitmap);
}
}

View File

@@ -0,0 +1,53 @@
package com.uiuipad.find.activity.main;
import android.graphics.Bitmap;
import com.blankj.utilcode.util.NetworkUtils;
import com.uiuipad.find.R;
import com.uiuipad.find.base.BaseActivity;
import butterknife.ButterKnife;
public class MainActivity extends BaseActivity implements MainAContact.MainView, NetworkUtils.OnNetworkStatusChangedListener{
private static final String TAG = MainActivity.class.getSimpleName();
private MainAPresenter mPresenter;
@Override
public void onDisconnected() {
}
@Override
public void onConnected(NetworkUtils.NetworkType networkType) {
}
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
@Override
public void initView() {
ButterKnife.bind(this);
mPresenter = new MainAPresenter(this);
mPresenter.setLifecycle(lifecycleSubject);
mPresenter.attachView(this);
NetworkUtils.registerNetworkStatusChangedListener(this);
}
@Override
public void initData() {
}
@Override
public void setQrCode(Bitmap bitmap) {
}
}

View File

@@ -64,12 +64,12 @@ public abstract class BaseActivity extends AppCompatActivity implements Lifecycl
UltimateBarX.statusBar(this)
.transparent()
.colorRes(R.color.colorPrimaryDark)
// .light(true)
.light(true)
.apply();
UltimateBarX.navigationBar(this)
.transparent()
.colorRes(R.color.colorPrimaryDark)
// .light(true)
.light(true)
.apply();
setContentView(this.getLayoutId());
initView();

View File

@@ -3,6 +3,8 @@ package com.uiuipad.find.comm;
public class CommonConfig {
public static final String MMKV_ID = "InterProcessKV";
public static final String AES_KEY = "0123456789ABCDEF";
public static final String MAP_LOCATION_JSON_KEY = "MAPLOCATION_JSON_STRING";
public static final String MAP_LONGITUDE_KEY = "map_longitude_key";
public static final String MAP_LATITUDE_KEY = "map_latitude_key";

View File

@@ -0,0 +1,68 @@
package com.uiuipad.find.util;
import android.graphics.Bitmap;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.HashMap;
import java.util.Map;
public class BitmapUtils {
public static Bitmap createQRImage(String content, int widthPix, int heightPix) {
try {
// if (content == null || "".equals(content)) {
// return false;
// }
//配置参数
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//容错级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置空白边距的宽度
hints.put(EncodeHintType.MARGIN, 1); //default is 4
// 图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = null;
try {
bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix,
heightPix, hints);
} catch (WriterException e) {
e.printStackTrace();
}
int[] pixels = new int[widthPix * heightPix];
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (int y = 0; y < heightPix; y++) {
for (int x = 0; x < widthPix; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * widthPix + x] = 0xff0480ff;
} else {
pixels[y * widthPix + x] = 0xffffffff;
}
}
}
// 生成二维码图片的格式使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
//
// if (logoBm != null) {
// bitmap = addLogo(bitmap, logoBm);
// }
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的
// 内存消耗巨大!
return bitmap;
// return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -0,0 +1,331 @@
package com.uiuipad.find.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CXAESUtil {
/**
* 加解密算法/工作模式/填充方式
*/
private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
public final static String HEX = "0123456789ABCDEF";
private static final int keyLenght = 16;
private static final String defaultV = "0";
/**
* 加密
*
* @param key 密钥
* @param src 加密文本
* @return
* @throws Exception
*/
public static String encrypt(String key, String src) {
// /src = Base64.encodeToString(src.getBytes(), Base64.DEFAULT);
byte[] rawKey = toMakekey(key, keyLenght, defaultV).getBytes();// key.getBytes();
try {
byte[] result = encrypt(rawKey, src.getBytes("utf-8"));
// result = Base64.encode(result, Base64.DEFAULT);
return toHex(result);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* 加密
*
* @param key 密钥
* @param src 加密文本
* @return
* @throws Exception
*/
public static String encrypt2Java(String key, String src) throws Exception {
// /src = Base64.encodeToString(src.getBytes(), Base64.DEFAULT);
byte[] rawKey = toMakekey(key, keyLenght, defaultV).getBytes();// key.getBytes();
byte[] result = encrypt2Java(rawKey, src.getBytes("utf-8"));
// result = Base64.encode(result, Base64.DEFAULT);
return toHex(result);
}
/**
* 解密
*
* @param key 密钥
* @param encrypted 待揭秘文本
* @return
* @throws Exception
*/
public static String decrypt(String key, String encrypted) throws Exception {
byte[] rawKey = toMakekey(key, keyLenght, defaultV).getBytes();// key.getBytes();
byte[] enc = toByte(encrypted);
// enc = Base64.decode(enc, Base64.DEFAULT);
byte[] result = decrypt(rawKey, enc);
// /result = Base64.decode(result, Base64.DEFAULT);
return new String(result, "utf-8");
}
/**
* 密钥key ,默认补的数字补全16位数以保证安全补全至少16位长度,android和ios对接通过
*
* @param str
* @param strLength
* @param val
* @return
*/
private static String toMakekey(String str, int strLength, String val) {
int strLen = str.length();
if (strLen < strLength) {
while (strLen < strLength) {
StringBuffer buffer = new StringBuffer();
buffer.append(str).append(val);
str = buffer.toString();
strLen = str.length();
}
}
return str;
}
/**
* 真正的加密过程
* 1.通过密钥得到一个密钥专用的对象SecretKeySpec
* 2.Cipher 加密算法,加密模式和填充方式三部分或指定加密算 (可以只用写算法然后用默认的其他方式)Cipher.getInstance("AES");
*
* @param key
* @param src
* @return
* @throws Exception
*/
private static byte[] encrypt(byte[] key, byte[] src) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] encrypted = cipher.doFinal(src);
return encrypted;
}
/**
* 真正的加密过程
*
* @param key
* @param src
* @return
* @throws Exception
*/
private static byte[] encrypt2Java(byte[] key, byte[] src) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] encrypted = cipher.doFinal(src);
return encrypted;
}
/**
* 真正的解密过程
*
* @param key
* @param encrypted
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] key, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
/**
* 把16进制转化为字节数组
*
* @param hexString
* @return
*/
public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
return result;
}
/**
* 二进制转字符,转成了16进制
* 0123456789abcdefg
*
* @param buf
* @return
*/
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
/**
* 初始化 AES Cipher
*
* @param sKey
* @param cipherMode
* @return
*/
public static Cipher initAESCipher(String sKey, int cipherMode) {
// 创建Key gen
// KeyGenerator keyGenerator = null;
Cipher cipher = null;
try {
/*
* keyGenerator = KeyGenerator.getInstance("AES");
* keyGenerator.init(128, new SecureRandom(sKey.getBytes()));
* SecretKey secretKey = keyGenerator.generateKey(); byte[]
* codeFormat = secretKey.getEncoded(); SecretKeySpec key = new
* SecretKeySpec(codeFormat, "AES"); cipher =
* Cipher.getInstance("AES"); //初始化 cipher.init(cipherMode, key);
*/
byte[] rawKey = toMakekey(sKey, keyLenght, defaultV).getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
cipher = Cipher.getInstance("AES");
cipher.init(cipherMode, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
} catch (NoSuchPaddingException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
} catch (InvalidKeyException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return cipher;
}
/**
* 对文件进行AES加密
*
* @param sourceFile
* @param sKey
* @return
*/
public static File encryptFile(File sourceFile, String toFile, String dir, String sKey) {
// 新建临时加密文件
File encrypfile = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(sourceFile);
encrypfile = new File(dir + toFile);
outputStream = new FileOutputStream(encrypfile);
Cipher cipher = initAESCipher(sKey, Cipher.ENCRYPT_MODE);
// 以加密流写入文件
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
byte[] cache = new byte[1024];
int nRead = 0;
while ((nRead = cipherInputStream.read(cache)) != -1) {
outputStream.write(cache, 0, nRead);
outputStream.flush();
}
cipherInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
} catch (IOException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace(); // To change body of catch statement use
// File | Settings | File Templates.
}
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace(); // To change body of catch statement use
// File | Settings | File Templates.
}
}
return encrypfile;
}
/**
* AES方式解密文件
*
* @param sourceFile
* @return
*/
public static File decryptFile(File sourceFile, String toFile, String dir, String sKey) {
File decryptFile = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
decryptFile = new File(dir + toFile);
Cipher cipher = initAESCipher(sKey, Cipher.DECRYPT_MODE);
inputStream = new FileInputStream(sourceFile);
outputStream = new FileOutputStream(decryptFile);
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = inputStream.read(buffer)) >= 0) {
cipherOutputStream.write(buffer, 0, r);
}
cipherOutputStream.close();
} catch (IOException e) {
e.printStackTrace(); // To change body of catch statement use File |
// Settings | File Templates.
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace(); // To change body of catch statement use
// File | Settings | File Templates.
}
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace(); // To change body of catch statement use
// File | Settings | File Templates.
}
}
return decryptFile;
}
}

View File

@@ -33,4 +33,6 @@ public class Utils {
}
return serial;
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".activity.main.MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".activity.main.MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".activity.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="colorPrimary">#efefef</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#4880ff</color>
<!-- <color name="colorPrimary">#6200EE</color>-->
<!-- <color name="colorPrimaryDark">#3700B3</color>-->
<!-- <color name="colorAccent">#03DAC5</color>-->
</resources>

View File

@@ -1,7 +1,7 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>