前言:记录下自己在收银机开发过程中的一些心得笔记,此博客长期更新。
00 收银机开发和普通安卓手机应用开发的区别 个人觉得,最大的区别就是,屏幕空间变大了,一屏之内可展示的内容变多了。其实不仅仅是屏幕空间变大了,也由原来的习惯看竖屏到习惯看横屏了。另外需要做的适配工作也简单很多,因为收银机屏幕分辨率和屏幕大小都差不多,几乎不需要做特殊的适配,而且你还可以更改屏幕密度,下面会说到。
还有一点就是,不再需要担心应用保活的问题了,因为基本上安装到商家的收银机上之后,我们的应用就是主角,所以可供我们发挥的空间就大了。另外诸如开机自启、系统敏感权限等,这些都不是事儿~
虽然少了很多限制,但还是想说,安全对一款收银机应用来说还是非常重要的,比如怎样保证应用的数据安全以及网络安全,这些都是目前还没来得及做、未来需要完善的。
01 应用全屏 PART 1 一般来说,我们的收银机应用大多数时候都应该占满屏幕,所以需要用到全屏模式:
1 2 3 4 5 6 7 8 <style name ="AppTheme" parent ="Theme.AppCompat.Light.NoActionBar" > <item name ="colorPrimary" > @color/colorPrimary</item > <item name ="colorPrimaryDark" > @color/colorPrimaryDark</item > <item name ="colorAccent" > @color/colorAccent</item > <item name ="android:windowAnimationStyle" > @style/notAnimation</item > <item name ="android:windowFullscreen" > true</item > <item name ="android:windowContentOverlay" > @null</item > </style >
可以看到我们使用了 Theme.AppCompat.Light.NoActionBar
作为父主题,然后覆盖了 android:windowFullscreen
和 android:windowContentOverlay
属性,前者用于隐藏状态栏,后者用于消除包裹应用 content 的 drawable(通常是标题下的阴影),参考 windowContentOverlay 。
PART 2 当然,这些只是最基本的,我们还需要处理 activity 配置发生改变的情况,在 activity 下添加:
1 android:configChanges="orientation|screenSize|keyboardHidden"
这样,我们就告诉系统当 activity 屏幕方向或者键盘可见性发生变化后不要退出重启 activity,因为收银机应用几乎所有 activity 屏幕方向都应该是水平的。
另外关于键盘,还需要在 activity 中加上 android:windowSoftInputMode="stateHidden|adjustPan"
属性,stateHidden
表明当用户初次进入 activity 的时候,键盘不会显示出来(一般只有在登录界面才会需要键盘一开始就显示),而 adjustPan
则会在键盘显示出来的时候自动调整 UI 内容,让用户始终可以看到他们输入的内容而不是被键盘覆盖掉。
所以 AndroidManifest 中我们的 activity 大多数是这样配置的:
1 2 3 4 <activity android:configChanges ="orientation|keyboardHidden|screenSize" android:screenOrientation ="landscape" android:windowSoftInputMode ="stateHidden|adjustPan" />
具体参数介绍请看 。
PART 3 这些就够了吗?当然不是!通常,我们还需要在我们的 BaseActivity 中做如下配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 final int fullScreenFlags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;final Window window = getWindow(); window.getDecorView().setSystemUiVisibility(fullScreenFlags); window.getDecorView().setOnSystemUiVisibilityChangeListener(new View .OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange (int visibility) { window.getDecorView().setSystemUiVisibility(fullScreenFlags); } });
可以看到我们给 DecorView 设置了一些 Visibility 的 Flag, 首先是隐藏状态栏和导航栏,然后是 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
用于沉浸模式,也就是使状态栏变得半透明,同时接受屏幕边缘的滑动事件(通常这类事件是由系统处理掉的)。文档上是这么写的:
While in sticky immersive mode, if the user swipes from an edge with a system bar, system bars appear but they’re semi-transparent, and the touch gesture is passed to your app so it app can also respond to the gesture.
然后是 View.SYSTEM_UI_FLAG_LAYOUT_STABLE
用于保证你的布局全屏,不会因为系统栏的显示而重新调整大小。具体请参考文档:Enable fullscreen mode
PART 4 除此之外,我们还应该考虑到一些特殊情况,比如显示 dialog 或者用户输入的情况下,这些时候导航栏都会显示出来,所以通常我们还会写这么一个方法:
1 2 3 4 5 6 7 8 9 10 public void enterFullScreen (Window window) { window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN; window.getDecorView().setSystemUiVisibility(uiOptions); }
然后在显示 dialog 或者其他一些有可能触发导航栏显示的地方调用下这个方法,这样就能保证始终全屏啦。另外对于监听键盘输入,推荐一个三方库:KeyboardVisibilityEvent ,使用起来非常方便,只要在 activity 初始化的地方调用:
1 2 3 4 5 6 7 KeyboardVisibilityEvent.setEventListener(this , new KeyboardVisibilityEventListener () { @Override public void onVisibilityChanged (boolean isOpen) { UIHelper.create().enterFullScreen(getWindow()); } });
这样当用户使用键盘输入的时候,我们可以保证始终全屏显示。
最后,也许有人会有疑问,如果我们的应用开机自启,而且始终全屏,那不是无法回到桌面了吗?其实不用担心,我们可以自己设置一个按钮,提供回到桌面的功能,比如当用户点击右下角显示当前时间的地方。是不是听起来有点熟悉?没错,就是受到了 windows 的启发~
02 修改收银机主屏幕密度 PART 1 首先说明下,这种方式只针对使用瑞芯 芯片的收银机才有效,可以用以下命令检查是否是支持修改:
1 2 3 adb shell cat /system/build.prop | grep ro.sf.lcd_density# or adb shell getprop ro.sf.lcd_density
如果存在该属性则证明可以修改。下面是步骤(过时,参考 PART 3):
将 /system/build.prop
文件拉到本地,使用 adb 命令:
1 adb pull /system/build.prop ./
打开 build.prop
文件,找到 ro.sf.lcd_density
属性,这个属性就是用来指定屏幕密度的,直接修改成我们想要的密度就可以了,默认是 160,我们可以修改为 240。个人觉得,对于一般收银机来说,这是看着最舒服的:
1 2 # set default lcd density to Rockchip tablet ro.sf.lcd_density=240
将修改完毕后的文件覆盖掉原文件,当然首先要将 /system
挂载为可读写再覆盖:
1 2 3 adb root adb shell mount -o rw,remount /system adb push build.prop /system/
最后不要忘记修改 /system
为只读:
1 2 adb shell mount -o ro,remount /system adb shell reboot
最后,当机子重启完毕,新的屏幕密度就已经起作用了。
PART 2 当然,上面这些步骤对于安卓开发来说没难度,但是对于运维来说,其实还是挺麻烦的,所以写了个 batch 脚本(运维用 Windows ¯\_(ツ)_/¯),只要用数据线连接上收银机,双击运行下就ok了,我是不是很棒~
Github 地址:ChangeDensity-win-batch
PART 3 其实修改屏幕分辨率还有一个更简便的方法,那就是通过 adb
命令中的 Window Manager,一行命令就可以搞定:
1 adb shell wm density [reset|DENSITY]
参数中 reset 表示恢复默认值,DENSITY 就是你想要修改成的屏幕密度,是不是异常简单?而且这种修改方式是立即生效的,和之前的方法一比简直不要太方便。同样只要检查 ro.sf.lcd_density
参数是否存在就可以了。另外,wm 全部命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 usage: wm [subcommand] [options] wm size [reset|WxH|WdpxHdp] wm density [reset|DENSITY] wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM] wm scaling [off|auto] wm screen-capture [userId] [true|false] wm size: return or override display size. width and height in pixels unless suffixed with 'dp'. wm density: override display density. wm overscan: set overscan area for display. wm scaling: set display scaling mode. wm screen-capture: enable/disable screen capture. wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if necessary. wm surface-trace: log surface commands to stdout in a binary format.
可以看到屏幕分辨率也是可以直接修改的:
1 adb shell wm size [reset|WxH|WdpxHdp]
新技能 GET✓ (•̀ᴗ•́)و ̑̑