sdk只支持本地引入aar,不支持maven方式接入
demo下载地址
sdk下载地址
若有权限问题,请查看SDK合作流程及规范。
在local.properties
中设置K歌开放平台的appId与appKey:
KTV_SDK_APP_ID=
# 正式环境appKey,没有则不填
KTV_SDK_APP_KEY=
# 测试环境appKey,没有则不填
KTV_SDK_TEST_APP_KEY=
KtvSDK默认是正式环境,如果需要手动切换sdk的环境,可在初始化sdk后,调用
KtvSdk.setProductEnv()
方法来切换,重启应用后生效。
在demo中,也可打开“SDK开发者设置”页,切换环境:
推荐运行环境:
KtvSdk通过aar的方式对外提供,三方按照aar的方式集成即可:
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation(name: 'library-name', ext: 'aar')
}
sync之后即可使用;
由于sdk依赖部分三方库,但未打包到sdk中,需要宿主在项目的build.gradle 文件中添加以下依赖
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3"
implementation "com.squareup.okhttp3:okhttp:3.12.0"
implementation "com.google.zxing:core:3.3.3"
implementation "com.tencent:mmkv:1.0.23"
implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementaion "androidx.constraintlayout:constraintlayout:2.0.1"
implementation "androidx.multidex:multidex:2.0.1"
implementation "com.google.code.gson:gson:2.6.2"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.21"
implementation("com.google.android.exoplayer:exoplayer-core:2.18.5") {
exclude group: 'androidx.core'
exclude group: 'androidx.annotation'
exclude group: 'androidx.fragment'
}
由于sdk已做混淆,因此app配置sdk相关类不混淆即可:
-keep class com.tme.**{*;}
-keep class com.tencent.karaoke.**{*;}
-keep class com.tencent.qmsq.**{*;}
-keep class com.tencent.news.**{*;}
-keep class com.tencent.threadpool.**{*;}
-keep class com.tencent.libunifydownload.**{*;}
-keep class com.tencent.karaoketv.**{*;}
-keep class com.tencent.qqmusic.business.lyricnew.**{*;}
-keep class com.ola.star.**{*;}
-keep class com.ola.qmsq.**{*;}
-keep class ksong.support.**{*;}
-keep class easytv.common.**{*;}
其余需要app主动依赖的三方开源库,按照三方库要求的混淆规则配置即可
建议在application中初始化:
KtvSdk.init(application: Application, ktvInitParams: KtvInitParams)
其中ktvInitParams是sdk初始化需要传入的参数, 主要设置内容如下:
data class KtvInitParams(
//宿主信息
val hostInfo: IKAppInfo,
//播放阻断相关处理
val appRequestProvider: AppRequestProvider,
//图片加载实现
val imageLoader: IKImageLoader,
//Android权限请求实现,一般不需要自定义,使用sdk内置实现即可
val permissionProvider: IKPermissionProvider? = null,
//日志实现,默认打印到logcat
var logger: IKLog? = null,
)
IKAppInfo
用于声明宿主app的基本信息。
public interface IKAppInfo {
/**
* appId,可向K歌开放平台申请获得
* 必传
* @return
*/
String getAppId();
/**
* 开放平台appkey,可向K歌开放平台申请获得
* 自实现登录方式不需要传
* @return
*/
String getAppKey();
/**
* 平台标识
* 车机:52
* 智能音箱或其它:53
* 必传
* @return
*/
String getPlatformId();
/**
* 厂商自己的设备id,必传
*/
String getImei();
/**
* 厂商用户id,可选
*/
String getUid();
/**
* 厂商渠道号,需改为真实的渠道号, 一般为appid
*/
String getChannelId();
/**
* 宿主是否为正式环境,必传
*/
boolean isProductEnv();
/**
* 是否为开发调试模式,若是,sdk内部应用一些开发调试配置,有助于问题定位,但对sdk性能可能有影响。
*/
boolean isDevMode();
/**
* app唯一版本标识,可选。非腾讯类的app不用传
*/
String getQua();
/**
* 要传给sdk的附加信息,可选
*/
Map<String, String> getExtraInfo();
}
HostInfo 参照demo中SampleHostInfo:继承KAppInfoAdapter,提供宿主信息,如果方法返回类型不可空,则属于必填参数,可空则不强制要求,如果有其他需要传入的设备信息,通过getExtraInfo的Map传入。
KtvSDK默认是正式环境,如果需要手动切换sdk的环境,可在初始化sdk后,调用
KtvSdk.setProductEnv()
方法来切换。
AppRequestProvider
全民K歌提供一天内免费唱几首的功能(具体次数与产品确认),当超过免费唱次数后,sdk会记录当前页面是播放页,会通过此接口回调播放阻断,app侧可以做相应的业务逻辑(如跳转会员页等)。
这里定义了一个通用请求接口(目前只有播放阻断的场景),方法签名如下:
fun request(
groupId: String,
eventType: String,
status: Any?,
extra: Map<String, Any>?
): Any?
参数说明:
参数 | 类型 | 说明 |
---|---|---|
groupId | String | 请求大类,标识属于哪一类请求,比如登陆、录唱、支付等 |
eventType | String | 请求类型,区分具体什么请求,如"guideUrl"代表获取mic引导链接 |
status | Any? | 请求状态,通用类型的请求参数,可为空 |
extra | Map<String, Any>? | 其他额外的请求参数放在Map中传入,可为空 |
返回值:返回true则表示此操作正在处理,APP可以跳到支付页,当支付完成后,让播放页露出时重新收到onStart()后,sdk的播放逻辑会继续执行,这样就可以续播。
返回false则表明已处理完成,sdk不再根据当前context监听onStart事件。
需要业务方根据传参提供具体实现。
初始化的方式参考demo中HostApp的initKG方法,但是AppRequestProvider需要业务方根据具体场景实现。
问题: 什么是播放歌曲阻断?
答案: 调用预加载或播放会触发对播放次数的统计,如果当前用户不是VIP会员,则播放VIP歌曲会直接触发歌曲播放阻断。其它歌曲都是限免歌曲,如果超过配置的限免数,就会报“限免达到上限”。
如播放歌曲阻断(如会员歌曲/免费歌曲达到次数上限等)时,sdk会通过此接口通知到app端,app侧可以做相应的业务逻辑(如跳转会员页等)
这种场景下:
groudId: "type_play"
eventType: "play_intercept"
status: 阻断原因,可能有如下值
interface InterceptType {
String UNKNOWN = "unknown";
String FREE_TRAIL = "free_limit"; //限免阻断,错误码50015
String VIP = "vip_limit"; //VIP阻断,错误码50016
String LOGIN = "login_limit"; //登录阻断, 错误码40010。仅自实现登录会回调,其它登录方式走LoginError回调错误。
String AUDIO_HQ_NEED_VIP = "AUDIO_HQ_NEED_VIP"; //音频HQ权益阻断,错误码50025
String VIDEO_1080P_NEED_VIP = "VIDEO_1080P_NEED_VIP"; //1080P权益阻断,错误码50026
String VIDEO_4K_NEED_VIP = "VIDEO_4K_NEED_VIP"; //4K权益阻断,错误码50027
}
示例:
override fun request(
context: Context,
groupId: String,
eventType: String,
status: Any?,
extra: Map<String, Any>?
): Any? {
if (groupId == "type_play" && eventType == "play_intercept") {
status.startActivity(Intent(this, SamplePlayListActivity::class.java))
}
return true
}
注意:另外需要在播放页的初始化时增加如下代码
PlayerManager.getPlayPermissionProvider()?.attachPage(activity)
如需要跳转到宿主的播放页的场景,此时:
groudId: "type_play"
eventType: "goto_play_page"
status: PendSong
客户端收到此回调时,主动跳转到播放页,并播放当前mid的歌曲
imageLoader
: 宿主需实现图片下载接口logger
: 宿主日志实现
fun initKG() {
val params = KtvInitParams(
hostInfo = SampleHostInfo(),
appRequestProvider = SampleAppRequestProvider(),
imageLoader = GlideImageLoaderImpl(),
logger = SimpleLog(),
)
KtvSdk.init(this, params)
//如果需要在测试环境测试,可设置sdk为测试环境
//KtvSdk.setProductEnv(false)
customConfig()
}
/**
* 播放可选配置,相关配置项都有默认值,一般不需要单独配置。
*/
private fun customConfig() {
KtvPlayerConfig.getInstance()
// // .useTextureView()
// .setCacheStrategyFactory(object : CacheStrategyFactory() {
// override fun createCacheStrategy(cacheDirPath: String): AbstractCacheStrategy {
// return LruCacheStrategy(cacheDirPath, 1024 * 1024 * 1024 * 2L) //设置硬盘缓存
// }
// })
// .forceUseSystemAudioOutput(true)
// .installAudioInstaller(PuremicOutputInstaller(),PuremicReceiverInstaller())
// .setKtvPlayerEventReportCallback { mid: String?, event: Int -> }
// .setSupportAudioRecordReceiver(true)
// .enableDebugLog(true)
// .enableDownloadLog(true)
// .downloadRetryCount(3) //下载重试次数
// .setUserAgent("Demo") //User-Agent
// .useOpenGL(false) //是否使用GLSurfaceView
.commit() //此方法必须被调用
}
sdk需要登录态才能唱歌。登录集成方式详见:KtvSDK-登录
播放器为KaraokePlayer
,播放界面自行开发。
如果有Android4.4的设备,要处理证书兼容性问题-KtvSDK-Android4.4设备G2证书兼容处理
播放相关的接口如下:
KaraokePlayer Api | Describe |
---|---|
void play(SongInfoObject object) | 播放歌曲 |
void pause() | 暂停播放 |
void resume() | 恢复播放 |
void stop() | 释放播放资源,相当于release。退出播放时调用;或播放下一首时,先调用stop()再调用play() |
void replay() | 重新播放 |
int getPlayState() | 播放状态 {VideoState.STATE_IDLE:0, VideoState.STATE_START:1, VideoState.STATE_PLAYING:2, VideoState.STATE_PAUSE:3, VideoState.STATE_ENDED:4} |
KaraokePlayer setDataSourceType(DataSourceType sourceType) | 切换原唱/伴奏 |
KaraokePlayer setLoopMode(LoopMode mode) | Loop or Once |
KaraokePlayer setTonePitchShift(int offset) | 设置升降调的值(-12到12) |
int getTonePitchShift( ) | 获取设置升降调的值(-12到12) |
DataSourceType getDataSourceType() | 获取伴奏类型 |
KaraokePlayer setVolume(float volume) | 设置伴奏音量(0.0-1.0f) |
KaraokePlayer setMicVolume(float volume) | 设置mic 音量(0.0-1.0f) |
float getVolume() | 获取伴奏音量 |
float getMicVolume() | 获取mic 音量 |
KaraokePlayer addCallback(KaraokePlayerListener callback) | 添加播放回调或播放器监听 |
KaraokePlayer removeCallback(KaraokePlayerListener callback) | 移除播放回调或播放器监听 |
KaraokePlayer addOnScoreListener(OnScoreListener listener) | 添加打分回调或打分监听 |
KaraokePlayer removeOnScoreListener(OnScoreListener listener) | 移除打分回调或打分监听 |
KaraokePlayer setFadeAudioVolumeTime(long time) | 渐变音时间 |
KaraokePlayer setFadeAudioEnable(boolean flag) | 是否允许渐变音 |
long getCurrentTime() | 当前解码时间, sdk内部使用,获取当前播放时间建议用getTimeLineTime() |
long getTimeLineTime() | 当前播放时间 |
long getDuration() | 歌曲总时长 |
KaraokePlayer setKtvVideoLayout(IVideoView videoLayout) | 设置视频View,详见下面介绍 |
void seek(long seekTimeMs) | seek功能,K歌时只能向后seek,播放纯MV时可快进快退 |
void setScoreInfo(KaraokeScoreInfo scoreInfo) | 设置歌词与打分需要的数据,在使用LyricInitializer初始化歌词信息后调用 |
long getPreludeFinishTime() | 前奏结束时间前5秒,用于显示跳过前奏 |
播放歌曲的步骤如下:
下面列出了详细步骤:
布局中加入视频View KtvVideoLayout:
<ksong.support.video.ktv.KtvVideoLayout
android:id="@+id/video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
不要对KtvVideoLayout进行多次addView/removeView操作,不然会出现视频黑屏现象。
播放页创建时,创建播放器实例,一个界面只用一个播放器,退出时销毁。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
createKaraokePlayer()
}
private fun createKaraokePlayer() {
if(currentPlayer == null) {
//KtvVideoLayout为视频View
val videoLayout: KtvVideoLayout = findViewById(R.id.ktv_video_layout)
//创建播放器实例
currentPlayer = KtvPlayerImpl()
currentPlayer.setKtvVideoLayout(videoLayout)
}
}
创建好播放器后,再根据下面"3.4.1 使用sdk请求歌曲信息"节的信息进行歌曲加载与播放。
厂商实现登录后,就可以只提供歌曲id,实现播放功能。
如果是预加载,只调用PlayManager.preload()接口即可。
...
//停止当前歌曲播放
player?.stop()
val builder = SongInfoObject.Builder()
builder.setMid(currentMid)
//设置歌曲类型,从SongType类取值,SongType类型详见下面介绍
builder.setSongType(songType)
val songInfoObject = builder.build()
//使用PlayerManager加载歌曲资源
PlayerManager.preload(songInfoObject) { event: PlayPreLoaderEvent ->
when (event) {
//预加载完成
is PlayPreLoaderEvent.Success -> {
val song = event.songInfoObject ?: return@preload
//进行播放
playSong(song)
}
//预加载的一些日志打印
is PlayPreLoaderEvent.Trace -> {
}
//歌曲加载进度
is PlayPreLoaderEvent.Progress -> {
}
//预加载失败
is PlayPreLoaderEvent.Failed -> {
Logger.i(TAG, "preload $event")
}
}
}
private fun playSong(songInfo: SongInfoObject) {
val player = currPlayer //创建播放器实例
//设置播放参数
player
.setTonePitchShift(0)
.setDataSourceType(dataSourceType)
.setMicVolume(PlayConsole.get().micVolume.value?.volume?.div(10.toFloat()) ?: 0.7F)
.setVolume(PlayConsole.get().accompanyVolume.value?.volume?.div(10.toFloat()) ?: 1.0F)
.addCallback(createCallback()) //添加播放回调
//调用play()
player.play(songInfo)
}
播放页实现示例详见Ktv SDK 播放功能接入说明。
更多歌词内容请见 KtvSDK-歌词
更多打分内容请见 KtvSDK-打分