首页
工具
隐私协议
作品
更多
关于我们
Search
1
proguard-rules出现unresolved class name
897 阅读
2
onActivityResult过时了,registerForActivityResult使用方法
866 阅读
3
FlexboxLayout+recyclerView实现自动换行
817 阅读
4
android5遇到INSTALL_FAILED_DEXOPT 解决办法
629 阅读
5
Room数据库Schema export Error
560 阅读
默认分类
mysql
android
android深入
Jetpack Compose
Android传感器
php
Yii2
windows
webrtc
登录
Search
标签搜索
android
kotlin
webrtc
kurento
nginx
flutter
adb
rsa
微信
git
mysql
Yii2
md5
加密
dart
aes
wechat
windows
小程序
dexopt
Kornan
累计撰写
72
篇文章
累计收到
3
条评论
首页
栏目
默认分类
mysql
android
android深入
Jetpack Compose
Android传感器
php
Yii2
windows
webrtc
页面
工具
隐私协议
作品
关于我们
搜索到
51
篇与
android
的结果
2020-08-17
Android加密算法之AES
什么是高级加密标准或AES?AES加密标准又称为高级加密标准Rijndael加密法,是美国国家标准技术研究所NIST旨在取代DES的21世纪的加密标准。AES加密如何工作?AES是一种对称的加密算法,可基于相同的密钥进行加密和解密。AES包含三个分组密码:AES-128,AES-192和AES-256。每个密码分别使用128 位,192位和256位的加密密钥对128 位块中的数据进行加密和解密。代码:object AESCrypt { private const val AES_MODE = "AES/CBC/PKCS7Padding" //"算法/模式/补码方式" private const val CHARSET = "UTF-8" private const val CIPHER = "AES" private const val HASH_ALGORITHM = "SHA-256" private val IV_BYTES = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) /** * Generates SHA256 hash of the password which is used as key * * @param password used to generated key * @return SHA256 of the password */ @Throws(NoSuchAlgorithmException::class, UnsupportedEncodingException::class) private fun generateKey(password: String): SecretKeySpec { val digest = MessageDigest.getInstance(HASH_ALGORITHM) val bytes = password.toByteArray(charset(CHARSET)) digest.update(bytes, 0, bytes.size) val key = digest.digest() return SecretKeySpec(key, CIPHER) } /** * Encrypt and encode message using 256-bit AES with key generated from password. * * @param password used to generated key * @param message the thing you want to encrypt assumed String UTF-8 * @return Base64 encoded CipherText * @throws GeneralSecurityException if problems occur during encryption */ @Throws(GeneralSecurityException::class) fun encrypt(password: String, message: String): String { try { val key = generateKey(password) val cipherText = encrypt(key, IV_BYTES, message.toByteArray(charset(CHARSET))) //NO_WRAP is important as was getting \n at the end return Base64.encodeToString(cipherText, Base64.NO_WRAP) } catch (e: UnsupportedEncodingException) { throw GeneralSecurityException(e) } } /** * More flexible AES encrypt that doesn't encode * * @param key AES key typically 128, 192 or 256 bit * @param iv Initiation Vector * @param message in bytes (assumed it's already been decoded) * @return Encrypted cipher text (not encoded) * @throws GeneralSecurityException if something goes wrong during encryption */ @Throws(GeneralSecurityException::class) fun encrypt(key: SecretKeySpec, iv: ByteArray, message: ByteArray): ByteArray { val cipher = Cipher.getInstance(AES_MODE) val ivSpec = IvParameterSpec(iv) cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec) return cipher.doFinal(message) } /** * Decrypt and decode ciphertext using 256-bit AES with key generated from password * * @param password used to generated key * @param base64EncodedCipherText the encrpyted message encoded with base64 * @return message in Plain text (String UTF-8) * @throws GeneralSecurityException if there's an issue decrypting */ @Throws(GeneralSecurityException::class) fun decrypt(password: String, base64EncodedCipherText: String): String { try { val key = generateKey(password) val decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP) val decryptedBytes = decrypt(key, IV_BYTES, decodedCipherText) return String(decryptedBytes, charset(CHARSET)) } catch (e: UnsupportedEncodingException) { throw GeneralSecurityException(e) } } /** * More flexible AES decrypt that doesn't encode * * @param key AES key typically 128, 192 or 256 bit * @param iv Initiation Vector * @param decodedCipherText in bytes (assumed it's already been decoded) * @return Decrypted message cipher text (not encoded) * @throws GeneralSecurityException if something goes wrong during encryption */ @Throws(GeneralSecurityException::class) fun decrypt(key: SecretKeySpec, iv: ByteArray, decodedCipherText: ByteArray): ByteArray { val cipher = Cipher.getInstance(AES_MODE) val ivSpec = IvParameterSpec(iv) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec) return cipher.doFinal(decodedCipherText) } }添加扩展方法,方便调用private const val key: String = "Your AES Key" fun encrypt(input: String): String { return AESCrypt.encrypt(key, input) } fun decrypt(input: String): String { return AESCrypt.decrypt(key, input) } fun String.aesEncrypt(): String = encrypt(this) fun String.aesDecrypt(): String = decrypt(this)使用方法"明文".aesEncrypt() "密文".aesDecrypt()
2020年08月17日
233 阅读
0 评论
0 点赞
2020-08-14
解决NestedScrollView嵌套RecyclerView滚动监听问题
不使用recyclerview的监听,直接用NestedScrollView的监听scrollView.setOnScrollChangeListener( NestedScrollView.OnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> if (scrollY > oldScrollY) { Log.i(TAG, "Scroll DOWN") } if (scrollY < oldScrollY) { Log.i(TAG, "Scroll UP") } if (scrollY == 0) { Log.i(TAG, "TOP SCROLL") } if (scrollY == v.getChildAt(0).measuredHeight - v.measuredHeight) { Log.i(TAG, "BOTTOM SCROLL") } })
2020年08月14日
258 阅读
0 评论
0 点赞
2020-08-14
android加密算法之MD5
方法1fun getMD5A(str: String): String? { return try { val md: MessageDigest = MessageDigest.getInstance("MD5")//生成一个MD5加密计算摘要 md.update(str.toByteArray()) //计算md5函数 var md5Str: String = BigInteger(1, md.digest()).toString(16) if (md5Str.length < 32) { md5Str = "0$md5Str" } md5Str } catch (e: Exception) { throw Exception("MD5加密出现错误") } }方法2,修改hexDigits可生所不同的字符串:例如:charArrayOf('5','2','0','1','3','1','4','7','8','9','a','b','c','d','e','f')fun getMD5B(str: String): String? { val hexDigits = charArrayOf('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f') return try { val mdInst = MessageDigest.getInstance("MD5") mdInst.update(str.toByteArray()) val md = mdInst.digest() val j = md.size val str = CharArray(j * 2) var k = 0 for (i in 0 until j) { val byte0 = md[i] str[k++] = hexDigits[byte0.toInt().ushr(4) and 0xf] str[k++] = hexDigits[byte0.toInt().and(0xf)] } String(str) } catch (e: java.lang.Exception) { e.printStackTrace() null } }
2020年08月14日
253 阅读
0 评论
0 点赞
2020-08-12
proguard-rules出现unresolved class name
最近将Android studio升级到4.0后,proguard-rules.pro文件出现许多错误,unresolved class name目前的解决办法是在开头加上#noinspection ShrinkerUnresolvedReference
2020年08月12日
897 阅读
0 评论
1 点赞
2020-08-06
getResources().getColor() is deprecated
getResources().getColor(android.R.color.white)过时了以下方法替换getResources().getColor(android.R.color.white, getActivity().getTheme()));或ContextCompat.getColor(context, R.color.color_name)
2020年08月06日
230 阅读
0 评论
0 点赞
2020-06-08
显示PopupMenu时滚动toolbar
我在Fragment里弹PopupMenu时会把toolbar向上滚动<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:id="@+id/coordinatorLayout"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="fixed" app:tabGravity="fill"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.design.widget.FloatingActionButton android:id="@+id/floatingButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:src="@drawable/ic_add" /> </android.support.design.widget.CoordinatorLayout>解决办法:PopupMenu popupMenu = new PopupMenu(MainActivity.this,view);替换成PopupMenu popupMenu = new PopupMenu(MainActivity.this,view, Gravity.RIGHT);
2020年06月08日
215 阅读
0 评论
0 点赞
2020-05-17
Caused by: android.view.InflateException: Binary XML file line #258: Error inflating class android.webkit.WebView
看到有部分机型出现了BUG,并有用户也反馈了升级后某页面无法打开:Caused by: android.view.InflateException: Binary XML file line #258: Error inflating class android.webkit.WebView回想一下新版本做的改动,有问题的页面也就是调整了下布局,而用了WebView的地方也只有Admob广告而已,这里并没有改动,Google了一会儿,原来罪魁祸首的是appcompat,旧版本用的是appcompat1.0.2,新版本用的是appcompat:1.1.0。具体原因不明,改回1.0.2后测试正常,用新的androidx.appcompat:appcompat:1.2.0-alpha03也没问题。解决方案:https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview
2020年05月17日
127 阅读
0 评论
0 点赞
2020-05-14
Waiting for another flutter command to release the startup lock
当我运行Flutter doctor时,它显示Waiting for another flutter command to release the startup lock一直卡在这里,网上搜搜:试了删除flutter/bin/cache/lockfile文件的,会提示文件被Dart.exe占用,而无法删除最后的解决方法:taskkill /F /IM dart.exe之后再运行就可以了,具体参考:stackoverflow
2020年05月14日
251 阅读
0 评论
0 点赞
2020-05-11
使用BottomSheetDialogFragment底部弹框
步骤1:为底页创建布局文件<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/dp_8" android:layout_marginTop="@dimen/dp_8" android:orientation="vertical"> <TextView android:id="@+id/tv_bottom_sheet_heading" android:layout_width="wrap_content" android:layout_height="@dimen/dp_56" android:layout_marginEnd="@dimen/dp_16" android:layout_marginStart="@dimen/dp_16" android:gravity="center" android:text="@string/bottom_sheet_option_heading" android:textColor="@color/md_bottom_sheet_title_color" android:textSize="16sp" /> <TextView android:id="@+id/tv_btn_add_photo_camera" android:layout_width="match_parent" android:layout_height="@dimen/dp_48" android:layout_marginEnd="@dimen/dp_16" android:layout_marginStart="@dimen/dp_16" android:backgroundTint="@android:color/white" android:drawablePadding="@dimen/dp_32" android:drawableStart="@drawable/ic_add_a_photo" android:drawableTint="@color/md_bottom_sheet_text_color" android:gravity="start|center_vertical" android:text="@string/bottom_sheet_option_camera" android:textColor="@color/md_bottom_sheet_text_color" android:textSize="16sp" /> <TextView android:id="@+id/tv_btn_add_photo_gallery" android:layout_width="match_parent" android:layout_height="48dp" android:layout_marginEnd="@dimen/dp_16" android:layout_marginStart="@dimen/dp_16" android:backgroundTint="@android:color/white" android:drawablePadding="@dimen/dp_32" android:drawableStart="@drawable/ic_gallery_photo" android:drawableTint="@color/md_bottom_sheet_text_color" android:gravity="start|center_vertical" android:text="@string/bottom_sheet_option_gallery" android:textColor="@color/md_bottom_sheet_text_color" android:textSize="16sp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginBottom="@dimen/dp_8" android:layout_marginTop="@dimen/md_bottom_sheet_separator_top_margin" android:background="@color/grayTextColor" /> <TextView android:id="@+id/tv_btn_remove_photo" android:layout_width="match_parent" android:layout_height="@dimen/dp_48" android:layout_marginEnd="@dimen/dp_16" android:layout_marginStart="@dimen/dp_16" android:backgroundTint="@android:color/white" android:drawablePadding="@dimen/dp_32" android:drawableStart="@drawable/ic_delete_photo" android:drawableTint="@color/md_bottom_sheet_text_color" android:gravity="start|center_vertical" android:text="@string/bottom_sheet_option_remove_photo" android:textColor="@color/md_bottom_sheet_text_color" android:textSize="16sp" /> </LinearLayout>步骤2:创建dimen.xml文件:<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="dp_8">8dp</dimen> <dimen name="dp_16">16dp</dimen> <dimen name="dp_24">24dp</dimen> <dimen name="dp_32">32dp</dimen> <dimen name="dp_40">40dp</dimen> <dimen name="dp_48">48dp</dimen> <dimen name="dp_56">56dp</dimen> <dimen name="dp_64">64dp</dimen> <dimen name="dp_72">72dp</dimen> <dimen name="dp_80">80dp</dimen> <dimen name="dp_160">160dp</dimen> <dimen name="md_bottom_sheet_separator_top_margin">7dp</dimen> </resources>步骤3:string.xml文件:<string name="bottom_sheet_option_camera">Use Camera</string> <string name="bottom_sheet_option_gallery">Upload from Gallery</string> <string name="bottom_sheet_option_heading">Add Photo</string> <string name="bottom_sheet_option_remove_photo">Remove Photo</string>步骤4:创建自定义BottomSheetDialogFragmentpublic class AddPhotoBottomDialogFragment extends BottomSheetDialogFragment{ public static AddPhotoBottomDialogFragment newInstance() { return new AddPhotoBottomDialogFragment(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.layout_photo_bottom_sheet, container, false); // get the views and attach the listener return view; } }步骤5:在Activity中弹出FragmentDialog:AddPhotoBottomDialogFragment addPhotoBottomDialogFragment = AddPhotoBottomDialogFragment.newInstance(); addPhotoBottomDialogFragment.show(getSupportFragmentManager(), "add_photo_dialog_fragment");就这样完成了:您可以在自定义底部工作表对话框片段中创建自定义回调接口,以在单击底部的按钮时通知Activity
2020年05月11日
333 阅读
0 评论
0 点赞
2020-04-21
Handler是如何传递消息的
先认识下跟Handler有关的几个类:MessageQueue,Message,Runnable,Looper。Runnable和Message可以被传入某个MessageQueue中;Looper不断地从MessageQueue中取出Object然后传给Handler进行处理,依次循环,如果队列为空,就会进入休眠;Handler利用自身的处理机制对传入的Object进行相应的处理。认识这几个类后,再了解下Handler和Thread的关系一个Thread对应一个Looper;一个Looper对应一个MessageQueue;一个MessageQueue对应N个Message;一个Message中对应一个Handle来处理事件;由此可以看出,Thread和Handler是一对多的关系;而Handler主要有两个功能,处理message和将message传入MessageQueue中。Looper从MessageQueue中取出一个Message后,首先会调用Handler.dispatchMessage进行消息分发,默认情况下Handler的分发流程是:Message.callback(Runnable obj) 如果不为空会优先调用callback处理Handler.mCallback 如果不为空会调用mCallback.handleMessage如果以上两个对象都不存在,则会调用Handler.handleMessage如果项目中有需要改变handler的默认行为,可以重载dispatchMessage或handleMessage。Handler发送消息有两种方式,分别是post和send,这两种方式都是负责将message传入MessageQueue,区别在于send处理的参数直接是message,而post需要先把其它信息转换成message,再调用send来执行下一步,看源码:public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r),0); }因为调用时会传一个Runnable对象,post需要先将其封装成一个Message,接着通过对应的send把它传到MessageQueue里。private static Message getPostMessage(Runnable r){ Message m=Message.obtain();//Android系统会维护一个全局的Message池,当用户需要使用Message时,可以调和obtain获得,不用去自行创建,这样可以避免不必要的资源浪费 m.callback=r;//将Runnable对象设置为Message的回调函数 return m; }拿到Message后,再调用sendMessageDelayed来发送消息,这个函数可设置多长时间后再发送,在其内部又调用sendMessageAtTime来发送。public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false } msg.target = this; return enqueueMessage(queue,msg,uptimeMillis);//将message传入MessageQueue }这样就将一条由Runnable组成的Message通过Handler成功传入MessageQueue。
2020年04月21日
178 阅读
0 评论
0 点赞
1
...
4
5
6