Skip to content

Commit

Permalink
Merge pull request #6 from quicktvui/dev
Browse files Browse the repository at this point in the history
优化首页小窗切换体验、详情页焦点问题
  • Loading branch information
zhaopengdev authored Apr 23, 2024
2 parents a179dd4 + d8f07cf commit dde260c
Show file tree
Hide file tree
Showing 60 changed files with 1,020 additions and 601 deletions.
17 changes: 6 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
[![vue version](https://img.shields.io/badge/vue-3.2-green.svg)](https://github.com/vuejs/core)
[![vue version](https://img.shields.io/badge/@quicktvui/quicktvui3-latest-green.svg)](https://www.npmjs.com/package/@quicktvui/quicktvui3?activeTab=versions)

基于 [QuickTVUI](http://v3.quicktvui.com/zh/) 专为快速打造安卓TV影视应用而开发的示例项目。
项目主要目的是让开发者通过对本项目的简单修改,实现一些TV端常见的功能页面,从而加速开发者开发TV类影视类应用。
主要页面包括瀑布流首页、媒资列表、搜索、视频观看详情等,以下是一些页面效果:
HelloTV是基于 [QuickTVUI](http://v3.quicktvui.com/zh/) 框架的视频点播直播应用,面向使用遥控器交互的安卓大屏设备。
项目目的是让开发者通过对本项目源码的简单修改,快速实现一些TV端常见的功能页面,从而加速开发进度。如果使用者并不具备编程能力,可以参考“HelloTV-Case”项目,简单修改该项目配置文件就可以快速实现一个标准化的视频类应用。
点播页面包括瀑布流首页、内容列表、筛选、搜索、详情、历史、收藏、登录等,直播页面包括多级列表页、播放详情页等。
以下是一些页面效果:

瀑布流首页
![image](https://extcdn.hsrc.tv/extend_screen/images/example_app/bgplay.png)
Expand All @@ -15,17 +16,11 @@
![image](https://extcdn.hsrc.tv/extend_screen/images/example_app/filter.png)
详情页
![image](https://extcdn.hsrc.tv/extend_screen/images/example_app/detail.png)
多级列表页
![image](doc/live1.png)
![image](doc/live2.png)
内容编辑页
![image](doc/edit.png)
<!-- [![Build Status](https://travis-ci.org/your-username/your-project.svg?branch=master)](https://travis-ci.org/your-username/your-project) -->
<!-- [![npm version](https://badge.fury.io/js/your-package.svg)](https://badge.fury.io/js/your-package) -->

> 目前项目仅供参考,代码逐步完善中,请暂勿用于正式项目中。
> release版本会于近期推出,敬请期待!


## 快速开始
Expand Down Expand Up @@ -87,11 +82,11 @@ npm run build-apk-release
- [x] 瀑布流首页
- [x] 搜索页
- [x] 媒资详情页
- [x] 筛选页(开发中)
- [x] 筛选页
- [x] 多级列表页
- [x] 一键打包生成APK

以上页面开发完成,正在debug中
以上页面开发完成,如发现问题,请提交issue

开发中
- [ ] 内容编辑页
Expand Down
101 changes: 87 additions & 14 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,37 @@ plugins {
}

ext {
// ----- APK相关配置 ----- //
APP_PACKAGE = 'com.quicktvui.hellotv' // APK包名
APP_NAME = 'HelloTV' // APK名字(Launcher显示)
APP_VERSION_CODE = 1 // APK版本code
APP_NAME = 'HelloTV' // 桌面显示名称
APP_VERSION_CODE = 1 // APK版本code(整数,最小为1,覆盖安装需要 >= 上次的code)
APP_VERSION_NAME = '1.0.0' // APK版本名称

BUILD_RPK_IN_APK = true // 是否将rpk打入apk(非assets加载方式不用打包进apk)
RPK_PACKAGE = "es.hellotv" // 生成的rpk包名
RPK_FILE_NAME = "hello.rpk" // 生成的rpk文件名
INCLUDE_SO = true // 将so打包进apk(首次启动不需要下载so文件,体积会变大,但首次启动会变快)
SO_ABI = ['armeabi-v7a', 'arm64-v8a'] // 包含SO的架构

// ----- RPK加载方式 ----- //
LOAD_TYPE = 1 // 加载方式:
// 1 从APK的assets中加载(只从apk中加载rpk,不会更新)
// 2 从指定路径加载
// 3 从url加载(适合url不变,只更新rpk包)
// 4 从指定源服务器加载

RPK_PACKAGE = "es.hellotv" // rpk包名(会按照这个包名进行本地版本管理)

// LOAD_MODULE修改后,只更改对应加载方式的配置即可

// 方式1:
RPK_FILE_NAME = "hello.rpk" // 自动生成的rpk文件名

// 方式2:
RPK_FILE_PATH = "data/data/$APP_PACKAGE/files/hello.rpk"

// 方式3:
RPK_FILE_URL = "https://extcdn.hsrc.tv/data_center/files/plugin/2024/04/18/efe23d2e-0c05-4dac-a77a-11635d6bbf12.zip"

// 方式4
REPOSITORY_HOST = "http://repo.quicktvui.com/"

vueDistDir = new File(project.rootDir, '../dist/android')
assetsDir = new File(project.buildDir, 'assets')
Expand All @@ -32,13 +54,10 @@ android {

multiDexEnabled true

buildConfigField 'String', 'RPK_PACKAGE', "\"${RPK_PACKAGE}\""
buildConfigField 'String', 'RPK_FILE_NAME', "\"assets://${RPK_FILE_NAME}\""

buildConfigField 'boolean', 'IS_BUILD_RPK_IN_APK', "$BUILD_RPK_IN_APK"
buildConfigField 'boolean', 'IS_INCLUDE_SO', "$INCLUDE_SO"

ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
abiFilters SO_ABI.toArray() as String[]
}
}

Expand All @@ -61,20 +80,33 @@ android {
signingConfig.initWith(buildTypes.debug.signingConfig)
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

android.sourceSets.findByName('main').assets.srcDirs += assetsDir

packagingOptions {
pickFirst 'lib/**/libc++_shared.so'
}
}

dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.appcompat:appcompat:1.0.0'

implementation 'com.extscreen.runtime:official:2.8.0.1'
implementation 'com.extscreen.runtime:official:2.8.0.5'
implementation 'eskit.sdk.support:video-cache-support:0.0.3-SNAPSHOT'

if (INCLUDE_SO) {
implementation 'eskit.sdk.support.so:hp-v1-armeabi-v7a:1.0.1'
implementation 'eskit.sdk.support.so:hp-v1-arm64-v8a:1.0.1'

implementation 'eskit.sdk.support.so:ijk-player-armeabi-v7a:1.0.0'
implementation 'eskit.sdk.support.so:ijk-player-arm64-v8a:1.0.0'
}
}

task deleteRpkCacheTask(type: Delete) {
Expand Down Expand Up @@ -105,21 +137,62 @@ task buildVue(type: Exec) {
dependsOn(buildVendor)
}

task writeConfigFile() {
doFirst {
assetsDir.mkdirs()
def sourceFile = new File(project.projectDir, "config.json")
def configMap = new groovy.json.JsonSlurper().parse(sourceFile, 'UTF-8')

configMap.put('version', 1)
configMap.put('load_type', LOAD_TYPE)
configMap.put('rpk_package', RPK_PACKAGE)

def uri = ''
def repo = ''
switch (LOAD_TYPE) {
case 1:
uri = "assets://${RPK_FILE_NAME}"
break
case 2:
uri = "file://${RPK_FILE_PATH}"
configMap.put('rpk_load_uri', )
break
case 3:
uri = RPK_FILE_URL
break
case 4:
repo = REPOSITORY_HOST
break
default:
throw new RuntimeException("unsupport LOAD_TYPE ${LOAD_TYPE}")
break
}

configMap.put('rpk_load_uri', uri)
configMap.put('repo', repo)

def json = groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(configMap))
new groovy.io.GroovyPrintStream(new FileOutputStream(new File(assetsDir, "config.json")), true, 'UTF-8').print(json)
}
}

task zipRpkTask(type: Zip) {
archiveName = RPK_FILE_NAME
destinationDir = assetsDir
from vueDistDir

dependsOn(buildVue)
dependsOn(buildVue, writeConfigFile)
}

afterEvaluate {

tasks.findByName('preBuild').dependsOn(deleteRpkCacheTask)

if(BUILD_RPK_IN_APK){
['generateDebugAssets', 'generateReleaseAssets'].each {
['generateDebugAssets', 'generateReleaseAssets'].each {
if (LOAD_TYPE == 1) {
tasks.findByName(it).dependsOn(zipRpkTask)
} else {
tasks.findByName(it).dependsOn(writeConfigFile)
}
}

Expand Down
11 changes: 11 additions & 0 deletions android/app/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"config": {
"local": {
"name": "",
"icon": "",
"zhibo": "",
"dianbo": ""
},
"remote": ""
}
}
23 changes: 4 additions & 19 deletions android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class com.quicktvui.hellotv.App {
public <methods>;
public <fields>;
}
52 changes: 46 additions & 6 deletions android/app/src/main/java/com/quicktvui/hellotv/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@
import androidx.multidex.MultiDexApplication;

import com.extscreen.runtime.EsKitInitHelper;
import com.google.gson.Gson;
import com.quicktvui.hellotv.config.Config;
import com.quicktvui.hellotv.config.ConfigModule;
import com.sunrain.toolkit.utils.FileUtils;
import com.sunrain.toolkit.utils.ToastUtils;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import eskit.sdk.core.InitConfig;
import eskit.sdk.core.internal.EsComponentManager;

/**
* <br>
Expand All @@ -13,17 +24,46 @@
*/
public class App extends MultiDexApplication {

public static ExecutorService sExecutor = Executors.newSingleThreadExecutor();
public static Config sConfig;

@Override
public void onCreate() {
super.onCreate();

initESKitSDK();
sExecutor.execute(WORK_INIT_CONFIG);
sExecutor.execute(WORK_INIT_SDK);
}

private void initESKitSDK() {
EsKitInitHelper.init(this, InitConfig.getDefault()
.addFlags(InitConfig.FLAG_DYNAMIC_SO)
);
}
private final Runnable WORK_INIT_CONFIG = new Runnable() {
@Override
public void run() {
try {
InputStream is = getAssets().open("config.json");
ByteArrayOutputStream ops = new ByteArrayOutputStream();
FileUtils.copy(is, ops);
String json = ops.toString();
sConfig = new Gson().fromJson(json, Config.class);
} catch (Throwable e) {
e.printStackTrace();
ToastUtils.showLong("获取配置文件失败 " + e.getMessage());
}
}
};

private final Runnable WORK_INIT_SDK = new Runnable() {
@Override
public void run() {
if(sConfig == null) return;

InitConfig initConfig = InitConfig.getDefault();
if (!BuildConfig.IS_INCLUDE_SO) {
initConfig.addFlags(InitConfig.FLAG_DYNAMIC_SO);
}

initConfig.setSdkInitCallback(() -> EsComponentManager.get().registerModule(ConfigModule.class));
EsKitInitHelper.init(App.this, initConfig);
}
};

}
Loading

0 comments on commit dde260c

Please sign in to comment.