## 一、管控APP功能分析 ### 1、包含的服务 #### 1.1、BackService 系统启动成功之后,如果打开酒店模式或者网络变化,就会打开TclIntentService,之后每半小时启动一次service。 #### 1.2、TclIntentService - 接受action为connect_server - - 接受index_order - - REQUEST_CHECK_APK ​ 自升级和更新 - - - SYSTEM_MODE_CHANGED 禁用APP,启用默认APP - - - REQUEST_CHECK_OTA ​ 检测OTA升级 - 接受action为com.android.systemservice.MANAGEMENT_APP ​ 禁用APP,启用默认APP #### 1.3、TvOnlineService - /api/tvlogs/tv_turn_on 上报数据 #### 1.4、AppOnlineService - /api/tvlogs/tv_app_turn_on 上报数据 #### 1.5、GrantService - action 为 com.tcl.grant.AUTH 或者 action 为com.android.systemservice.auth.CHANGED ​ 延迟20s之后,如果酒店模式打开了,调用 /api/terminal2 接口 进行注册。 注册成之后调用 /api/heartbeat2 获取在线授权信息。然后按照接口返回的心跳时间进行下一次操作。 - 应用自升级(应用平台) ### 2、包含的广播 #### 2.1、ManagementReceiver - 启动成功或者收到TCL 的P0广播 - - 启动 TclIntentService ,action 为 ACTION_MANAGEMENT_APP, 禁用APP,启用默认APP - 如果开启酒店模式,发送com.tcl.grant.AUTH,启动GrantService - 检查授权信息 - 启动成功 - - 启动 TvOnlineService ,调用 /api/tvlogs/tv_turn_on - 启动 AppOnlineService,调用 /api/tvlogs/tv_app_turn_on - 如果开启酒店模式,发送com.tcl.grant.AUTH,启动GrantService - 检查APP更新,检查OTA更新 - 收到TCL P0广播 - - 注册网络变化广播 - 启动TclIntentService,action为 connect_server,index_order 为 SYSTEM_MODE_CHANGED,禁用APP,启用默认APP - 网络变化或者酒店模式改变 - - 启动TclIntentService,action为 connect_server,index_order 为 SYSTEM_MODE_CHANGED,禁用APP,启用默认APP - 如果开启酒店模式,发送com.tcl.grant.AUTH,启动GrantService - 检测USB挂载 检查U盘更目录下的 /installation/installation文件的installation字段,如果是true就打开GrantActivity #### 2.2、TclBroadcastReceiver - 启动成功 - - 启动 BackService -> 启动TclIntentService ​ action 为 connect_server,index_order 为 REQUEST_CHECK_ALIVE 空实现 - 网络变化或者action为ACTION_OTA_TEST(com.android.systemservice.OTA_TEST) - - 启动 BackService -> 启动TclIntentService ​ action 为 connect_server,index_order 为 REQUEST_CHECK_ALIVE 空实现 - - 启动TclIntentService,action为 connect_server ,附带参数 index_order 分别为 REQUEST_CHECK_APK,REQUEST_REGISTER,REQUEST_CHECK_OTA - - REQUEST_CHECK_APK 调用 api/upgrade 接口下载和更新apk - - - REQUEST_REGISTER ​ 空实现 - - - REQUEST_CHECK_OTA ​ ota升级逻辑 - 检测USB端口挂载 本地离线授权 - 检测外设摄像头插拔 ​ 插:展示摄像头信息,拔:关闭摄像头 ### 3、主要功能汇总 #### 3.1、自更新和升级,包括应用平台 #### 3.2、APK管理,包括禁用和启用 #### 3.3、检测OTA升级(管控后台) #### 3.4、向/api/tvlogs/tv_turn_on 上报数据(可以考虑去掉) #### 3.5、向/api/tvlogs/tv_app_turn_on 上报数据(可以考虑去掉) #### 3.6、酒店注册 /api/terminal2 #### 3.7、获取在线授权信息 /api/heartbeat2 #### 3.8、本地离线授权和在线授权结合 #### 3.9、检测外设摄像头挂载(暂时没有用到,) ## 二、963和920差异对比 ### 1、TclIntentService com.android.systemservice.server.TclIntentService ``` //920上的实现 private List getDisableList(AppInfo info, String softVersion) { //这里不一致 if (info == null || softVersion == null || softVersion.trim().length() == 0) { return null; } String ver = softVersion.substring(0, 7); Log.i(TAG, "ver:" + ver); switch (ver) { case Constants.SOFT_VERSION_A260: return info.getDisableA26X(); case Constants.SOFT_VERSION_A360: return info.getDisableA36X(); case Constants.SOFT_VERSION_G5X://这里不一致 return info.getDisableG5X();//这里不一致 default: return info.getDisable(); } } //963上的实现 private List getDisableList(AppInfo info, String softVersion) { //这里不一致 if (info == null || softVersion == null || softVersion.trim().length() < 7) { return null; } String ver = softVersion.substring(0, 7); Log.i(TAG, "ver:" + ver); switch (ver) { case Constants.SOFT_VERSION_A260: return info.getDisableA26X(); case Constants.SOFT_VERSION_A360: return info.getDisableA36X(); case Constants.SOFT_VERSION_T972://这里不一致 return info.getDisableA26X(); //这里不一致 default: return info.getDisable(); } } ``` ### 2、Constants com.android.systemservice.utils.Constants ``` //920 public static final String SOFT_VERSION_A260 = "V8-S38P"; public static final String SOFT_VERSION_A360 = "V8-A962"; public static final String SOFT_VERSION_G5X = "V8-A920"; //963 public static final String SOFT_VERSION_A260 = "V8-S38P"; public static final String SOFT_VERSION_A360 = "V8-A962"; public static final String SOFT_VERSION_T972 = "V8-A972"; public static final String ANDROID = "android"; ``` ### 3、AppInfo com.tcl.app.AppInfo ``` //920 public List getDisableG5X(){ return DisableAppG5X.list; } AwesomeHotelDisable@add public void add() { awsomeHotelDisable.add(AWSOME_HOTEL2); awsomeHotelDisable.add(APP_MANAGER); awsomeHotelDisable.add(UPDATE); } DisableAppA26X#list public List list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client", "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast", "com.hpplay.allcast", "com.huan.edu.lexue.frontend", "com.tcl.browser", "com.audiocn.kalaok.tv", "com.android.keychain", "com.tcl.SmartTVHelp", "com.tcl.bootadservice", "com.tcl.tv.jtq", "com.tcl.esticker", "com.tcl.appmarket2", "cn.wps.moffice_i18n_TV", "com.tcl.tshop", "com.tcl.weixin", "com.tcl.screensaver", "com.tcl.common.weather", "com.tcl.usagestats", "com.tcl.usercenter", "com.tcl.vod", "com.tcl.wholenetsearch", "com.tcl.gamecenter", "com.golive.cinema", "com.tcl.tvweishi"); DisableAppA36X#list public final List list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client", "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast", "com.hpplay.allcast", "com.tcl.tshop", "com.golive.cinema", "com.audiocn.kalaok.tv", "com.tcl.weixin", "com.tcl.vod", "com.tcl.tvhealthcheck", "cn.wps.moffice_i18n_TV", "com.tcl.browser", "com.tcl.bootadservice", "com.tcl.screensaver", "com.tcl.usagestats", "com.tcl.tv.jtq", "com.tcl.gamecenter", "com.tcl.triava", "com.tcl.common.weather", "com.tcl.wholenetsearch", "com.tcl.SmartTVHelp", "com.huan.edu.lexue.frontend", "com.tcl.voicemanager", "com.tcl.usercenter", "com.tcl.tvweishi"); DisableAppG5X#list public static final List list = Arrays.asList("com.pptv.tvsports.preinstall","com.tcl.wholenetsearch", "com.tcl.initsetup","com.tcl.common.weather","com.golive.cinema","com.tcl.browser", "com.tcl.appmarket2","com.tcl.tshop","com.android.tcl.messagebox", "com.tcl.vod","com.tcl.weixin","com.tcl.SmartTVHelp","com.tcl.gamecenter", "com.tcl.usercenter","com.tcl.tvweishi","com.tcl.ffeducation","com.tcl.c2dm.client", "com.tcl.usagestats"); //963 AwesomeHotelDisable@add public void add() { awsomeHotelDisable.add(AWSOME_HOTEL); awsomeHotelDisable.add(AWSOME_HOTEL2); awsomeHotelDisable.add(APP_MANAGER); } DisableAppA26X#list public List list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client", "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast", "com.hpplay.allcast", "com.tcl.tvweishi", "com.huan.edu.lexue.frontend", "com.tcl.browser", "com.audiocn.kalaok.tv", "com.android.keychain", "com.tcl.SmartTVHelp", "com.tcl.bootadservice", "com.tcl.tv.jtq", "com.tcl.esticker", "com.tcl.appmarket2", "cn.wps.moffice_i18n_TV", "com.tcl.tshop", "com.tcl.weixin", "com.tcl.screensaver", "com.tcl.common.weather", "com.tcl.usagestats", "com.tcl.usercenter", "com.tcl.vod", "com.tcl.wholenetsearch", "com.tcl.gamecenter", "com.golive.cinema"); DisableAppA36X#list public final List list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client", "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast", "com.hpplay.allcast", "com.tcl.tvweishi", "com.tcl.tshop", "com.golive.cinema", "com.audiocn.kalaok.tv", "com.tcl.weixin", "com.tcl.vod", "com.tcl.tvhealthcheck", "cn.wps.moffice_i18n_TV", "com.tcl.browser", "com.tcl.bootadservice", "com.tcl.screensaver", "com.tcl.usagestats", "com.tcl.tv.jtq", "com.tcl.gamecenter", "com.tcl.triava", "com.tcl.common.weather", "com.tcl.wholenetsearch", "com.tcl.SmartTVHelp", "com.huan.edu.lexue.frontend", "com.tcl.voicemanager", "com.tcl.usercenter"); ``` ### 4、ManagementReceiver com.tcl.broadcast.ManagementReceiver ``` //963比920多了 //在ACTION_BOOT_COMPLETED之后 应用自升级检测 ota升级检测 ``` ### 5、GrantActivity com.tcl.grant.GrantActivity 以963方式为主 ``` //920 private void initGrantInfo(){ mMac = TVUtils.getEthMacAddress(); mGrantInfo = new DeviceInfo(); mGrantInfo.setMac(mMac==null?mMac:mMac.replace(":","")) .setMachineType(TVUtils.getModelName(getApplicationContext())) .setVersion(HotelUtils.getAgencyVersion(getApplicationContext())) .setVer(TVUtils.getSoftwareVersion()) //这里 .setLauncher(mLauncher); } //963 private String getSoftwareVersion() { if (mCustomerApiHandler.getCustomerApi() != null) { try { return mCustomerApiHandler.getCustomerApi().getSoftwareVersion(); } catch (Exception e) { e.printStackTrace(); } } return TVUtils.getSoftwareVersion(); } ``` ### 6、HotelUtils com.tcl.hoteltv.factory.HotelUtils (此方法使用920的方式,但是要改动) ``` //920 public static String getDefaultAgencyVersion(Context context){ StringBuilder builder = new StringBuilder(); builder.append("TCL-") .append(TVUtils.getModelName(context)) // .append("G60") .append("-20200325-V000"); return builder.toString(); } //963 public static String getDefaultAgencyVersion(Context context) { StringBuilder builder = new StringBuilder(); builder.append("TCL-") //.append(TVUtils.getModelName(context)) .append("G60") .append("-20200325-V000"); return builder.toString(); } ``` ### 7、TVUtils com.tcl.hoteltv.factory.TVUtils (用920的方式,需要验证) ``` //920 public static String getModelName(Context context) { String versionName = getSoftwareVersion(); if (versionName.contains(Constants.SOFT_VERSION_G5X)) { return FactoryManager.getInstance(context).doGetProjectName(); } else { return TDeviceInfo.getInstance().getModelName(getProjectIDValue(context)); } } //963 public static String getModelName(Context context) { return TDeviceInfo.getInstance().getModelName(getProjectIDValue(context)); } ``` ### 8、Files com.tcl.utils.Files ``` //920 public static void changePermission(String path){ FileUtils.setPermissions(path, FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IRWXO, -1, -1) ; } //963 public static void changePermission(String path){ MyFileUtils.setPermissions(path); //FileUtils.setPermissions(path, FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IRWXO, -1, -1) ; } ``` ### 9、jar包整理 #### 两个机型都有的jar包: ah-extension-1.0.1.aar 920文件md5:0794a887e3b80205854a3e3a4edc346d - 963文件md5:0794a887e3b80205854a3e3a4edc346d appassistsdk-2.0.11.aar 920文件md5:a53bb0b822fb8245855bdcdf3add9783 - 963文件md5:a53bb0b822fb8245855bdcdf3add9783 com.tcl.customerapi.jar 920文件md5:75802fa86e077513cf058db99cf4359f - 963文件md5:469bca8de85ca2c19c6ba9557e850425 com.tcl.tvos.addon.jar 920文件md5:2621d0f692fc8c4c83e8750efe5b5bfc - 963文件md5:2621d0f692fc8c4c83e8750efe5b5bfc factory.jar 920文件md5:3a3895919fb0a80e93eae9ea8402536f - 963文件md5:3a3895919fb0a80e93eae9ea8402536f fastjson-1.1.51.android.jar 920文件md5:24295b91c61c7a64dcba6b5518915867 - 963文件md5:24295b91c61c7a64dcba6b5518915867 framework.jar 920文件md5:4146ff34d7040bc93470e6adddf9439a - 963文件md5:4146ff34d7040bc93470e6adddf9439a services.jar 920文件md5:327debb1084d31350e4b721adea601b8 - 963文件md5:327debb1084d31350e4b721adea601b8 snack-1.0.2.aar 920文件md5:cc2f1a12750505b0777e0e93d6be8a07 - 963文件md5:cc2f1a12750505b0777e0e93d6be8a07 tornado-0.1.4.jar 920文件md5:01817d2b50ad9f5bfd1871095c208ee5 - 963文件md5:01817d2b50ad9f5bfd1871095c208ee5 tvapi.jar 920文件md5:45949462ec4ec42ac6eb5d84ffe7da72 - 963文件md5:45949462ec4ec42ac6eb5d84ffe7da72 zxing-core-3.3.3.jar 920文件md5:3ee2c714be5d25ac6c9b941f666bfea6 - 963文件md5:3ee2c714be5d25ac6c9b941f666bfea6 #### 仅963有的jar包 - rainbow-0.1.jar - virtualApi-0.1.jar ## 三、合并方案 ### 1、合并方式 有三种合并方式。 一种是不动代码结构,仅根据两者差异在差异点进行不同机型的适配,根据两个项目中源码对比的结果来看,此方法是可行的。此方法优点在于改动量小,而且基本能保证之前的功能。 第二种是大改代码结构,将整个项目进行重构,根据功能进行模块划分和重组。此方法的优点是可以趁机统一下代码风格,缺点是周期长,改动大,而且可能会丢失之前已经存在的功能。 第三种是前两者的结合,首先使用第一种方式完成不同机型的兼容。对项目内的部分功能点进行抽离和整理。 我个人建议采用第三种方式。 ### 2、建议抽离的功能点 #### 2.1、更新功能 包括应用自升级和ota升级的逻辑可以抽离到一起,提供统一入口 #### 2.2、数据上报相关 提供统一的入口,定时进行数据上报。包括注册和心跳 #### 2.3、授权相关 ## 离线授权和在线授权的整合