Android 机顶盒TV app开发
文章目录
- 1 TV项目开发步骤
- 1.1 普通apk开发流程
- 1.2 系统apk开发流程
- 2 焦点处理
- 2.1 TV开发中常见的遥控器事件KeyEvent
- 2.2 使用adb命令模拟遥控器按键调试TV模拟器
- 2.3 焦点拦截事件分发
- 2.3.1 事件传递说明
- 2.3.2 常见的焦点处理方式
- 2.3.3 View的焦点处理
- 2.3.4 遥控器长按事件监听
- 2.3.5 焦点丢失问题
- 3 adb参考
- 3.1 adb命令大全
- 3.2 apk正式签名步骤
- 3.3 使用adb命令将apk写入机顶盒相关命令
1 TV项目开发步骤
1.1 普通apk开发流程
- 连接机顶盒
// 10.118.4.144为机顶盒的ip,默认为5555端口
// 机顶盒ip一般在电视中的Network Setting中查看
// 使用adb需要连接网线通过网口连接
>>adb connect 10.118.3.56.5555
- 将apk写入机顶盒
// 使用adb install将写入data/data目录
>>adb install D:\android\test.apk// 强制覆盖安装apk,两种安装apk方式都是写入data/data目录,不适用于系统apk
>>adb install -r D:\android\test.apk // 当连接多台机顶盒时,将apk写入指定ip的机顶盒
>>adb -s 10.118.3.56:5555 install D:\android\test.apk
- 卸载apk
// 通过指定包名卸载apk
>>adb uninstall com.example.test
- 查看打印日志
// 查看输出为TAG关键字的log,这里的TAG相当于Log.i(TAG, "xxx")中的TAG
>>logcat -s TAG// 查看输出为TAG关键字的log,附带上时间
>>logcat -v time -s TAG// 查看输出为TAG关键字的log,这里的TAG可以为任意值
>>logcat | grep TAG
1.2 系统apk开发流程
/system分区默认挂载为只读,但有些操作比如给Android系统添加命令、删除自带应用等需要对/system进行写操作,所以需要重新挂载它为可读写。
写入的apk需要使用系统签名文件进行签名。
- 申请root权限
>>adb root
>>su
- 进入shell
>>adb shell
- 关闭内核打印
echo 0 > /proc/sys/kernel/printk
- 重新挂载
// mount命令是进入shell才可以使用
// 重新挂载vendor目录为可读写
>>mount -o rw,remount /vendor;
// 重新挂载system目录为可读写
>>mount -o rw,remount /system;// 如果上面的方式不能成功挂载,退出shell,通过adb remount挂载
>>exit
>>adb remount// 挂载对应的设备
>>adb -s 10.118.3.41:5555 remount
- 将apk push到系统目录下
// adb push可以替换原来的apk或者写入新的apk
>>adb push D:\android\demo\test.apk /system/app/test.apk
- 重启让apk生效
>>adb shell reboot>>adb -s 10.118.3.41:5555 shell reboot
- 测试应用
// 启动包名com.example.test下的MainActivity
>>adb shell am start -n com.example.test/.MainActivity// 主动发送广播
>>adb shell am broadcast -a android.intent.action.xxxx
2 焦点处理
2.1 TV开发中常见的遥控器事件KeyEvent
KeyEvent.KEYCODE_DPAD_UP:遥控器上键
KeyEvent.KEYCODE_DPAD_DOWN:遥控器下键
keyEvent.KEYCODE_DPAD_LEFT:遥控器左键
keyEvent.KEYCODE_DPAD_RIGHT:遥控器右键
keyEvent.KEYCODE_DPAD_CENTER:遥控器ok确认键
keyEvent.KEYCODE_DPAD_x:x表示数字0-9,遥控器数字键
KeyEvent.KEYCODE_BACK:遥控器返回键
KeyEvent.KEYCODE_HOME:遥控器主页键
KeyEvent.KEYCODE_x:x表示字母A-Z,遥控器字母键
KeyEvent.KEYCODE_MENU:遥控器菜单键
2.2 使用adb命令模拟遥控器按键调试TV模拟器
https://blog.csdn.net/u013347784/article/details/78329221
adb shellinput keyevent 1 // 遥控器menu键
input keyevent 3 // 遥控器Home键
input keyevent 4 // 遥控器Back键
input keyevent 19 // 遥控器上键
input keyevent 20 // 遥控器下键
input keyevent 21 // 遥控器左键
input keyevent 22 // 遥控器右键
input keyevent 23 // 遥控器ok确认键
2.3 焦点拦截事件分发
https://blog.csdn.net/jun5753/article/details/78684049
TV端是通过遥控器按键控制焦点事件,与手机端有所不同,所以在事件拦截处理上也不同。
手机端拦截事件分发:
dispatchTouchEvent()
onInterceptTouchEvent()
onTouchEvent()
TV端拦截事件分发:
dispatchKeyEvent()
onKeyDown()/onKeyUp()
onKeyListener()
2.3.1 事件传递说明
(PhoneWindow)$DecorView.dispatchKeyEvent()->Activity.dispatchKeyEvent()->View.dispatchKeyEvent()->// setonKeyListener != null则回调监听器
View.setOnKeyListener.onKey()->// setOnKeyListener == null或onKey()返回false则回调onKeyDown()/onKeyUp()
View.onKeyDown()/onKeyUp()->// setOnClickListener != null && 遥控器ok按键的ACTION_UP则回调监听器
View.setOnClickListener.onClick()->// View.setOnClickListener == null则返回到Activity回调onKeyDown()/onKeyUp()
Activity.OnKeyDown()/OnKeyUp()
KeyEvent的事件处理只有两个地方,一个是Activity,一个是具体的View,ViewGroup只负责分发事件给子View不消耗事件。其实Activity和具体View的事件处理都是交由DecorView处理。
2.3.2 常见的焦点处理方式
- 在Activity重写dispatchKeyEvent()
// 遥控器按下和松开会分别调用两次dispatchKeyEvent(),dispatchKeyEvent->onKeyDown->dispatchKeyEvent->onKeyUp
// 返回true或false都会拦截事件,即子View将不会接收到分发事件,Activity的onKeyDown()/onKeyUp()也不会接收到
// return true:拦截事件,不让焦点再移动
// return false:拦截事件,焦点会移动
// return super.dispatchKeyEvent:往下分发事件不拦截
@Override
public boolean dispatchKeyEvent(KeyEvent event) {int keyCode = event.getKeyCode();int action = event.getAction();switch(keyCode) {case KeyEvent.KEYCODE_DPAD_DOWN:if (action == KeyEvent.ACTION_DOWN) {Log.i(TAG, "dispatchKeyEvent-ACTION_DOWN");} else if (action == KeyEvent.ACTION_UP) {Log.i(TAG, "dispatchKeyEvent-ACTION_UP");}return true;case KeyEvent.KEYCODE_DPAD_UP:if (action == KeyEvent.ACTION_DOWN) {Log.i(TAG, "dispatchKeyEvent-ACTION_DOWN");} else if (action == KeyEvent.ACTION_UP) {Log.i(TAG, "dispatchKeyEvent-ACTION_UP");}return false;}return super.dispatchKeyEvent(event);
}
- 在Activity重写onKeyDown()/onKeyUp()
事件走到这两个回调表示子View没有消耗事件抛回给上层,在这里做最后的事件处理。
- 具体View实现setOnKeyListener()
一般实现onKeyListener对具体的遥控器事件做特殊处理
- 具体View实现OnClickListener()
一般实现onClickListener都是响应遥控器的ok确认键
2.3.3 View的焦点处理
requestFocus():强制获取焦点
android:focusable:设置一个控件是否能获取焦点
android:nextFocusUp/view.setNextFocusUpId(id):设置遥控器按上键时哪个view会获取到焦点,提供一个id
android:nextFocusDown/view.setNextFocusDownId(id):设置遥控器按下键时哪个view会获取到焦点,提供一个id
android:nextFocusLeft/view.setNextFocusLeftId(id):设置遥控器按左键时哪个view会获取到焦点,提供一个id
android:nextFocusRight/view.setNextFocusRightId(id):设置遥控器按右键时哪个view会获取到焦点,提供一个id
view.setOnFocusChangeListener():监听view获取到焦点,一般在该方法处理view背景修改等
2.3.4 遥控器长按事件监听
private boolean isLongPress;@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {isLongPress = true;return true;}return super.onKeyLongPress(keyCode, event);
}// dispatchKeyEvent统一处理长按时按下和松开时的处理
// 或者分别在onKeyDown监听长按按下,onKeyUp监听长按松开
@Override
public boolean dispatchKeyEvent(KeyEvent event) {int keyCode = event.getKeyCode();int action = event.getAction();switch(keyCode) {case KeyEvent.KEYCODE_DPAD_DOWN:if (action == KeyEvent.ACTION_DOWN) {// 按下时会执行一次,进行event长按跟踪,不断回调dispatchKeyEvent,第二次开始会走elseif (event.getRepeatCount() == 0) {event.startTracking();isLongPress = false;} else {isLongPress = true;// 遥控器向下长按按下处理.....}} else if (action == KeyEvent.ACTION_UP) {if (isLongPress) {isLongPress = false;// 遥控器向下长按松开处理....}}return true;}return super.dispatckKeyEvent(event);
}或者@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {if (event.getAction() == KeyEvent.ACTION_DOWN) {// 按下时会执行一次,进行event长按跟踪if (event.getRepeatCount() == 0) {isLongPress = false;event.startTracking();}return true;}}return super.onKeyDown(keyCode, event);
}@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {if (isLongPress) {isLongPress = false;// 遥控器向下长按松开处理....}return true;}return super.onKeyUp(keyCode, event);
}
2.3.5 焦点丢失问题
android:descendantFocusability="afterDescendants"
在组合控件(即自定义ViewGroup inflate有多个控件的xml布局)焦点处理中,在使用ListView、GridView、RecyclerView时有时会出现焦点丢失问题,需要添加该属性
// ViewGroup会优先其子类控件而获取焦点
android:descendantsFocusability="beforeDescendants"// ViewGroup只有当其子类控件不需要获取焦点时才获取焦点
android:descendantsFocusability="afterDescendants"// ViewGroup会覆盖子类控件而直接获得焦点
android:descandantsFocusability="blockDescendants"
3 adb参考
3.1 adb命令大全
https://github.com/mzlogin/awesome-adb
3.2 apk正式签名步骤
https://jingyan.baidu.com/article/59703552aeccbf8fc1074075.html
3.3 使用adb命令将apk写入机顶盒相关命令
https://www.jianshu.com/p/225fef8c6e67
Android 机顶盒TV app开发相关推荐
- Android兼容性系统app开发的一些探究
Android兼容性系统app开发的一些探究 说明 起因 软件现状 需求 实现探究 第一点:软件兼容原则 第二点:软件实现方案 具体实现 说明 说明 本文是我根据自己开发期间项目需求探究的总结,里面有 ...
- android电视盒子设备名字,Android电视TV盒子开发——常用ADB命令-Go语言中文社区...
目前智能电视(TV).盒子(机顶盒)基本都是Android系统,所以开发盒子app的重任自然就会落到我们这些苦逼Android程序员身上. PS:目前盒子的Android版本绝大部分还都是在6.0以下 ...
- Android电视TV盒子开发——常用ADB命令
目前智能电视(TV).盒子(机顶盒)基本都是Android系统,所以开发盒子app的重任自然就会落到我们这些苦逼Android程序员身上. PS:目前盒子的Android版本绝大部分还都是在6.0以下 ...
- Android入门 简单app开发:为女友实现记录月经周期的app
前言 寒假答应给女友做一个记录月经周期的app,由于我太vegetable,写的比较辣鸡,大家凑活着看(手动笑哭) 思路: 首先要跟大家说的是, android开发 要明白开发思想:逻辑和视图是分开的 ...
- Android短视频app开发中如何实现上下滑动切换效果
在大部分短视频app开发中,都会在app内增加上下滑动切换视频的功能,即下滑切换到下一条短视频,上滑切回到上一条.这种机制可以给用户带来良好的视觉体验,云豹作为优秀的app源码供应商,在该效果的实现上 ...
- 基于Android的理财app开发,基于Android的个人理财系统的设计与实现.doc
毕业论文(设计)题目: 基于Android的个人理财系统 ---设计与实现 学生姓名: 学 号: 专业班级: 计算机科学与技术092班 指导教师: 职称 副教授 指导教师: 职称 起止时间: 目 录 ...
- Android——“i 分享”APP开发Day06
继续上一篇的内容,写FindFragment.java文件,在上一篇的三个函数基础上基本就可以展示出热门内容了,接下来主要就是处理找人和找文按钮的事件 因为之后还需要实现找人的功能,所以要先给创建一个 ...
- Android 外卖订餐APP开发
APP展示页面: 本产品适用范围: 购买便利店系统任何版本,如需进行二次开发,需要单独联系我们队APP进行修改和调试,免收服务费用.本司接收任何 ...
- android 平面图app_Android App 开发技术图谱
引言: 今天偶然看到StuQ的技术图谱, 找了找竟然没有Android开发的. 想起之前自己弄了一个, 翻出来看看并不过时, 整理下发出, 大家共同进步. 图片比较大, 加载较慢, 请等待~~ And ...
最新文章
- 对不起,作为导师,我让您失望了!
- NO_CHANGE_ALLOWED error code
- Spring思维导图,让Spring不再难懂(ioc篇)
- 测试Java EE 8规范
- 外键为','(逗号)拼接ID,连接查询外键表ID
- 35岁,搞过超高并发架构,依然没看懂字节的推荐系统!
- hibernate连接mysql 释放连接_SSH 占用数据库连接不释放问题
- 中国传媒大学计算机学院夏令营,中国传媒大学夏令营
- 字体设计灵感合集|字体决定了设计
- c语言学习-判断一个年份是否闰年
- Qt实现多语言切换 - Qt语言家
- redis集群原理及搭建
- 哈工大车万翔团队:口语语言理解的最新进展与前沿
- 红米(RedmiBook)笔记本无线网卡QCA6174在Linux下wifi异常解决方法
- nlp对语料进行分类_如何使用nlp对推文进行分类
- 手机QQ与Win8:一蠢再蠢的改版与回炉
- vue使用XSLX,用CDN引入后下载的excel文件无法打开的解决办法
- 安装包UI美化之路-nsNiuniuSkin安装包模板介绍-新模板上线啦
- VUE强制渲染,强制更新
- 谷歌的无痕模式有什么好处_为什么Google的新搜索结果设计是黑暗的模式
热门文章
- 【EduCoder实训答案】大数据系统及应用-HDFS实训
- react总结之jsx是什么,jsx语法规则
- Linux查看服务器配置命令
- 中智集团携手亚信安全 打造立体化、智能化网络防御体系
- 2020.8 复习 7-11 分钟秒钟的时间相减 //PTA
- 中国计算机大赛游戏,我校在第10届全国大学生计算机设计大赛第暨4届中国大学生动漫游戏设计大赛,“星雨杯”福建省级赛的表现优异...
- 面试必备:四种经典限流算法讲解
- 作为一个新人,怎样学习嵌入式Linux ?(韦东山)
- 港联证券:为什么会出现股票跌停?股票跌停应该怎么卖出?
- JavaScript 中 的等号(==)/不等号(!=) 和全等号(===)/非全等号(!==)