技术小黑屋

一个检测 Json 合法性的脚本

越来越多的配置都是使用 json 的格式,当我们修改好,最好是进行一下 json 合法性校验。

我们可以使用下面的脚本进行校验。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env ruby
# encoding: utf-8
require 'json'
file = ARGV[0]


def is_json_valid(value)
  result = JSON.parse(value)
    result.is_a?(Hash) || result.is_a?(Array)
  rescue JSON::ParserError, TypeError
    false
  end


result = is_json_valid(File.open(file).read)
puts "json is valid(#{result})"

Flutter(Dart) 中将 2022-01-05 09:33:44 +0000 UTC 转成 Datetime

在日常的开发中,进行日期转换是比较常用的。但是对于新接触 Flutter 的话,对这个日期2022-01-05 09:33:44 +0000 UTC 使用DateTime.parse直接转换,会有问题,如下。

1
print(DateTime.parse('2022-01-05 09:33:44 +0000 UTC'));

当我们运行后,会得到这样的崩溃stacktrace

1
2
3
4
5
6
7
8
Unhandled exception:
FormatException: Invalid date format
2022-01-05 09:33:44 +0000 UTC
#0      DateTime.parse (dart:core/date_time.dart:330:7)
#1      testDateFormat (file:///Users/xxx/IdeaProjects/dart_sample/bin/dart_sample.dart:38:18)
#2      main (file:///Users/xxx/IdeaProjects/dart_sample/bin/dart_sample.dart:26:3)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:295:32)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

Mac 清理优化工具 MacBooster 限时特惠,终生版 7 折低至 41.3 元起

Mac 用户越来越多,针对 Mac 的病毒木马也逐渐出现了,Mac 电脑无需安全优化工具的历史似乎已成为过去。但部分清理工具升级迭代快,价格也很昂贵。

今天给大家推荐一款价格实惠、功能强大的 macOS 系统清理优化工具:MacBooster。一站式清理、查杀病毒及残余文件,优化系统加速运行。

https://asset.droidyue.com/image/lizhi_io/mac_booster/%E5%9B%BE1.png

Mac 上优秀的虚拟机软件 Parallels Desktop

使用 Mac 电脑,我们有时会碰到一些只在 Windows 平台下运行的软件。开发者们也时常会遇到安全性未知的软件,这时一个不影响工作环境的系统就很重要。

除了安装双系统,虚拟机就是解决上述这些问题的利器之一。而在 macOS 平台下,Parallels Desktop 可是虚拟机工具的不错选择。它是 macOS 平台性能首屈一指的虚拟机工具,软件搭载了各种常见和使用的工具,让您在 Mac 和 Windows 中能够很好地完成日常任务。

现在购买,享有优惠,具体请查看这里Parallels Desktop 17 – Mac 上优秀的虚拟机软件 PD 激活码 赠送Win11

Mac 终端下 实现 安装 Ipa 包到 iPhone 真机

最近处理 Flutter 的开发工作,开始尝试使用 iOS 作为日常的真机调试工作。对于一个原技术栈为 Android的人来说,发现 iOS 有很多不太方便的地方。比如如何在 Mac 电脑上安装 ipa包到 iPhone 上。

相比来说,Android 提供了adb 可以很快捷的在 终端上执行安装。而iOS 我也希望有一个可以在终端上实现安装ipa的方式,摸索了一下,终于发现了一个可行的技术方案。

Slack 设置代li

Slack 作为一个不错的团队协作沟通工具,被很多的团队采用。但是有时候网络并不是那么的好,需要让 Slack 走带理

但是 Slack 并没有提供 可视化的设置界面和选项。

不过经过一些摸索,发现还是有一些办法的。

Synergy 为你的键鼠升个级,一套键盘鼠标轻松控制多台电脑!

如果你的桌子上放置了多台电脑,为了分别控制每台设备,最常规的操作就是为每一台都插上一套键鼠,而此时你的桌面也被多个键盘鼠标占去了很大一部分空间。

不仅看起来凌乱,放在一起还不太容易区分哪套键鼠控制哪个设备。

111

今天要分享的 Synergy,不需要添置硬件、反复插拔键鼠,纯软件实现一套键盘鼠标连接控制多台电脑。不管你的键盘鼠标是什么品牌 / 型号,有线或是无线,甚至笔记本键盘、触控板都能直接用。

Flutter/Dart 获取当前的 Stacktrace

出现异常时获取 stacktrace

1
2
3
4
5
6
7
void _printException() {
 try {
   1 ~/ 0;
 } catch (e, s) {
   print('_printException $e; $s');
 }
}

对应的 stacktrace 日志信息

1
2
3
4
5
_printException IntegerDivisionByZeroException; #0      int.~/ (dart:core-patch/integers.dart:30:7)
#1      _printException (file:///Users/androidyue/Documents/self_host/dart_current_stacktrace/bin/dart_current_stacktrace.dart:10:7)
#2      main (file:///Users/androidyue/Documents/self_host/dart_current_stacktrace/bin/dart_current_stacktrace.dart:3:3)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:281:32)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

使用 Flutter SDK 中的 Dart SDK

由于 Flutter 是基于 Dart 的UI开发框架,在 Flutter SDK 中是包含了 Dart SDK的。

一般 Dart 的sdk 的路径为 your_flutter_dir/bin/cache/dart-sdk 将上面的 your_flutter_dir 替换为本机真实的路径即可。

比如: /Users/xxx/Documents/bin/flutter/bin/cache/dart-sdk

Edge 浏览器 复制 URL 问题解决

微软的 edge 浏览器作为第二浏览器在使用,目前发现唯一不好的,就是复制链接的时候,内容不对。

我的预计是复制网址本身,而不是标题和网址等内容,想要实现这一需求,也很简单。

步骤:

Preferences –> Share, Copy and Paster –> URL copy & paste format default 选择 Plain Text 即可。

iTerm2 (Mac Terminal) 清空当前屏幕内容

对于经常使用终端的开发者,清空当前屏幕的内容,我们可以使用clear

clear 清空屏幕内容,大多数情况下会满足我们的需求,但是某些场景下还是会有一些问题。

  • 向上滑动,还是能够看到之前的终端内容。
  • 比如我们搜索当前屏幕中的字符,clear 之前的内容还是会被清理掉

Kotlin Kapt Error: Identifier Expected 问题记录

在工作中,小伙伴说他遇到了一个 kapt的问题,在使用 gradle 构建的时候出现了如下的错误。

1
2
3
4
5
6
7
Kapt worker classpath: []
/Users/androidyue/Documents/SecooComponentMaster/module-xxxx/build/tmp/kapt3/stubs/debug/com/xxxxx/xxxxx/util/PlayerCommandStateManager.java:7: error: <identifier> expected
    private static final java.util.Map<java.lang.String, com.xxxxxx.xxxxxxx.util.const.PlayerCommandState> recordMap = null;
                                                                                    ^/Users/androidyue/Documents/xxxxxxx/module-xxxxxx/build/tmp/kapt3/stubs/debug/com/xxxxx/xxxxxx/util/PlayerCommandStateManager.java:7: error: <identifier> expected
    private static final java.util.Map<java.lang.String, com.xxxxxx.xxxxxxxx.util.const.PlayerCommandState> recordMap = null;
                                                                                                            ^/Users/androidyue/Documents/xxxxxxx/module-xxxxxx/build/tmp/kapt3/stubs/debug/com/xxxxx/xxxxxxx/util/PlayerCommandStateManager.java:7: error: <identifier> expected
    private static final java.util.Map<java.lang.String, com.xxxxxx.xxxxxxx.util.const.PlayerCommandState> recordMap = null;

对应的实际代码为

1
2
3
object PlayerCommandStateManager {
    private val recordMap = mutableMapOf<String, PlayerCommandState>()
}
1
2
3
4
5
6
7
8
9
10
package com.secoo.gooddetails.util.const

enum class PlayerCommandState {
    PAUSE_BY_USER,
    PAUSE_NORMAL,
    PLAY,
    INITIAL,
    ENDED,
    IDLE
}

Gson NoClassDefFoundError 问题解决

最近升级了gson到 2.8.6(2.8.7),结果发生了崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
E AndroidRuntime: FATAL EXCEPTION: PushConnectivityManager
E AndroidRuntime: Process: io.rong.push, PID: 11278
E AndroidRuntime: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/gson/Gson;
E AndroidRuntime:  at io.rong.push.rongpush.RongPushCacheHelper.cacheRongPushIPs(RongPushCacheHelper.java:44)
E AndroidRuntime:  at io.rong.push.core.PushNaviClient.connect(PushNaviClient.java:152)
E AndroidRuntime:  at io.rong.push.core.PushNaviClient.connectToNavi(PushNaviClient.java:93)
E AndroidRuntime:  at io.rong.push.core.PushNaviClient.getPushServerIPs(PushNaviClient.java:85)
E AndroidRuntime:  at io.rong.push.rongpush.PushConnectivityManager.connectToNavi(PushConnectivityManager.java:398)
E AndroidRuntime:  at io.rong.push.rongpush.PushConnectivityManager.access$200(PushConnectivityManager.java:34)
E AndroidRuntime:  at io.rong.push.rongpush.PushConnectivityManager$DisconnectedState.processMessage(PushConnectivityManager.java:234)
E AndroidRuntime:  at io.rong.push.common.stateMachine.StateMachine$SmHandler.processMsg(StateMachine.java:966)
E AndroidRuntime:  at io.rong.push.common.stateMachine.StateMachine$SmHandler.handleMessage(StateMachine.java:789)
E AndroidRuntime:  at android.os.Handler.dispatchMessage(Handler.java:110)
E AndroidRuntime:  at android.os.Looper.loop(Looper.java:219)
E AndroidRuntime:  at android.os.HandlerThread.run(HandlerThread.java:67)
E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.gson.Gson" on path: DexPathList[[zip file "/data/app/com.xxxxx-GXNVWX-EHV4m1HU42XJIgw==/base.apk"],nativeLibraryDirectories=[/data/app/com.xxxxx-GXNVWX-EHV4m1HU42XJIgw==/lib/arm, /data/app/com.xxxxx-GXNVWX-EHV4m1HU42XJIgw==/base.apk!/lib/armeabi-v7a, /system/lib, /hw_product/lib]]
E AndroidRuntime:  at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:209)
E AndroidRuntime:  at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
E AndroidRuntime:  at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
E AndroidRuntime:  ... 12 more

如何在 Android Studio(北极狐) 下增加仓库声明

最近升级了 Android Studio,变成了 Arctic Fox 的版本了。于是当我们新建一个项目的时候,尝试添加一个新的仓库声明。

打开工程根目录下的 build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

ProtoPie 无代码原型工具恢复上架,享荔枝半价优惠,仅需 429 元

ProtoPie 是一款界面美观、功能强大的无代码原型工具,支持 macOS 与 Windows 双平台。轻松组合即可制作交互动效,摆脱代码束缚。

它能够帮助设计师,无需编程快速地制作出高保真交互原型。还能实时在手机上演示,使原型能够在更多的场景下被使用。

https://asset.droidyue.com/image/2021/08/%E5%9B%BE1.png

ProtoPie 现与数码荔枝再度合作重新上架,官网原价 859 元,现在仅需 429 元。通过 [合作伙伴] 专属链接,下单就能享受 5 折特惠价,新注册用户再享 5 元立减优惠:马上购买


Ubuntu下 /usr/lib/* 内容恢复

有一次处理 Ruby 的版本问题,删除了/usr/lib/ruby文件夹,然后导致了ruby 出现各种问题。

那么怎么解决呢,重做系统,其实大可不必。在 Ubuntu 下使用这个方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
raw_pkgs = `dpkg --get-selections`.split("\n")
need_reinstall = []

path="/usr/lib/ruby"

raw_pkgs.each do |x|
    pkg = x.split(" ")[0]
    if `dpkg -L #{pkg}`.include? path
        puts "-> #{pkg} has files in #{path}"
        need_reinstall << pkg
    end
end
puts "\nYou need to reinstall #{need_reinstall.size} packages:"
puts "\tsudo apt-get install --reinstall " + need_reinstall.join(" ")

Gcc-6 G++-6 无法安装问题解决

在 Ubuntu 20.04 安装gcc-6和g++-6 遇到这样的问题

1
2
3
4
5
6
7
8
9
10
11
sudo apt-get install gcc-6 g++-6 -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package gcc-6 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Package g++-6 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

TransactionTooLargeException 问题分析与解决

在处理 App 崩溃时,有一种崩溃问题着实难以解决,甚至是令人挠头。比如像是今天将讨论的TransactionTooLargeException。下面就是该异常出现时的 stacktrace 信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
java.lang.RuntimeException: Adding window failed
at android.view.ViewRootImpl.setView(ViewRootImpl.java:548)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
... 16 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

在上面的 stacktrace 中 我们 没有找到任何应用相关的代码信息,这让解决这类问题变得更加棘手。

Curl 设置代理,看这篇就够了

curl 是一个很有名的处理网络请求的 类Unix 工具。出于某种原因,我们进行网络请求,需要设置代理。本文讲全面介绍如何为 curl 设置代理。

设置代理参数

基本用法

1
-x, --proxy [protocol://]host[:port]

Android WebView 获取网页源码 实践与问题解决

出于某些场景需要,有时候,我们需要从 WebView 获取源码,本文将简单介绍如何从 WebView 中获取源码,以及遇到的问题的分析和总结。

获取源码的方法

  • WebView 没有提供直接获取网页源码的方法
  • 我们需要使用Javascript 的方法来获取源码,具体的核心代码如下
1
2
3
4
function() {
    var content = document.getElementsByTagName('html')[0].innerHTML;
    return '<html>' + content + '</html>';
})