简体中文 | English
nTv is a landscape Android TV player for 18 CCTV HLS channels: CCTV-1 through
CCTV-17 and CCTV-5+. It targets Android 4.1 (minSdk 16), uses pure Java for
the application layer, and plays through ijkplayer 0.8.8. The application ID
is xiao.bu.tv.
- Quark cloud drive (access code:
KDmk)
The app starts an HTTP proxy on 127.0.0.1, rewrites the upstream m3u8, and
feeds the rewritten URL to ijkplayer. TS segments are downloaded by the proxy
and passed to JNI before ijkplayer sees them. Channel entry URLs request up to
the 4 Mbps range, and the proxy selects the highest bandwidth variant from the
master playlist so large TVs prefer the clearest available feed.
The JNI layer extracts H.264 PES payloads while retaining a byte-to-TS offset
map. It follows the call order in
xiaoxi-ij478/cctv-h5e-decrypt:
initialize player state, update the per-NAL tag, invoke the selected VOD
decryptors, and finish with CNTV_jsdecVOD8. Decrypted NAL bytes are written
back into the original TS positions, so no remux step is needed during live
playback. The JNI layer also freezes the worker-visible clock for each TS
segment so slower Android TV devices match the upstream worker's fast execution
behavior.
The wasm payload has already been converted into native C with WABT wasm2c.
The generated code lives in app/src/main/jni/generated.
The remote-control interaction follows WebViewTvLive:
DPAD_UPandDPAD_DOWNswitch channels during playback.DPAD_CENTER,ENTER, orMENUopens the channel list.BACKorMENUcloses the channel list.- The channel list closes automatically after five seconds without input.
MEDIA_PLAY_PAUSEpauses or resumes playback.- Tapping the video opens the channel list on touchscreen devices.
- Pressing
BACKtwice within two seconds exits the app when the list is closed.
The launcher icon is reused from WebViewTvLive.
Requirements:
- Android SDK with platform
android-27 - JDK 8
- Gradle
4.4 - Android NDK with Linux
armeabi-v7atoolchain - WSL when using the bundled Linux NDK from Windows
Create local.properties from local.properties.example, then build the
native library:
powershell -ExecutionPolicy Bypass -File .\scripts\build-native.ps1 `
-NdkRoot C:\path\to\android_ndkBuild the debug APK:
$env:JAVA_HOME = 'C:\path\to\jdk-8'
.\gradlew.bat assembleDebugWhen local.properties points to a Linux SDK under WSL, run Gradle inside WSL:
wsl -e bash -lc "cd /mnt/c/path/to/nTv && ./gradlew assembleDebug"The APK is generated at app/build/outputs/apk/debug/app-debug.apk.
Release builds automatically use the IPTV certificate when these local files exist inside the project:
.signing/iptv-release.jks
.signing/keystore-info.properties
The properties file uses this format (replace each placeholder locally):
keystore=iptv-release.jks
alias=<key alias>
storePassword=<keystore password>
keyPassword=<key password>The complete .signing/ directory is ignored by Git because it contains the
private key and passwords. Build the signed release APK with:
$env:JAVA_HOME = 'C:\path\to\jdk-8'
.\gradlew.bat assembleReleaseThe signed APK is generated at app/build/outputs/apk/release/app-release.apk.
The app checks version.json on startup. Both the manifest request and the APK
download are sent through https://gh-proxy.com/. When versionCode is newer
than the installed build, the app asks for confirmation, downloads the APK,
verifies its SHA-256 when provided, and opens Android's package installer.
The app does not request Android's REQUEST_INSTALL_PACKAGES permission.
It targets API 25 so the legacy installer intent remains available without that
manifest permission. Android 8.0+ can still require the user to approve this app
as an installation source; that system security confirmation cannot be bypassed.
The update endpoint is:
https://gh-proxy.com/https://github.com/buhanzhe/NativeWasmTv/raw/refs/heads/master/version-iptv.json
Create the release asset as nTv.apk, upload it to the GitHub Release whose tag
matches v<versionName> (for example v1.1.0), then generate the repository
manifest from that exact APK:
$env:JAVA_HOME = 'C:\path\to\jdk-8'
.\gradlew.bat generateVersionFile `
'-PupdateApk=C:\path\to\nTv.apk' `
'-PreleaseNotes=本次更新说明'Commit and push the generated version.json after publishing the matching APK.
The repository and Release asset must be publicly accessible because
gh-proxy.com cannot authenticate to a private GitHub repository. Always pass
-PupdateApk for a published release so clients can reject corrupted downloads.
Android 4.4 has TLS 1.2 support but does not enable it consistently. The app's TLS compatibility layer enables TLS 1.2 and compatible ECDHE/AES cipher suites for the update service and existing HTTPS playback requests.
The checked-in native C was generated from upstream commit
c56afb59bc4cf176acb137f7182c400565e0c4fa. To regenerate it after updating
that repository, download WABT 1.0.39 for Windows and run:
powershell -ExecutionPolicy Bypass -File .\scripts\extract-wasm.ps1 `
-WorkerJs C:\path\to\cctv.worker.new.js `
-WabtRoot C:\path\to\wabt-1.0.39The extracted wasm SHA-256 for the checked-in conversion is
b645471c0b114f4a385c7432002d46f409f1766b0c424f770afb6c921abc66ce.
- The current build packages
armeabi-v7a, which is suitable for Android 4.1+ TV devices and phones with that ABI. - Hardware decoding is enabled on Android 4.1+.
- The proxy intentionally falls back to the original segment when it cannot recognize an H5E stream or cannot perform an in-place NAL replacement.
- A trapped wasm call rejects that segment instead of passing encrypted bytes to ijkplayer, and resets the native wasm state before the next request.
- Use the player only with streams you are authorized to access.