N
O
D
E
M
E
D
I
A
Thinking
首页
产品
文档
博客
订单
文档
快速接入-Compose
2026年 5月 20日 下午3:52
## 简介 新应用开发,当前推荐使用Jetpack Compose 来接入。开发入门:https://developer.android.com/compose Jetpack Compose 是 Android 推荐的用于构建原生用户界面的现代化开发工具包。它简化并加快了在 Android 上的用户界面开发过程。通过更少的代码、强大的工具和直观的 Kotlin API,您可以迅速让您的应用程序焕发生机。 NodeMediaClient-Android 4.0+ 支持通过Jetpack Compose 进行开发接入。 ## 接入步骤 ### 1.向settings.gradle.kts 添加jitpack.io的maven ``` dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url = uri("https://jitpack.io") } } } ``` ### 2.在build.gradle.kts中添加依赖, 实际版本号以最新版本为准 ``` dependencies { implementation 'com.github.NodeMedia:NodeMediaClient-Android:4.0.11' } ``` ### 3.在页面组件内添加摄像头或播放器的封装视图 ``` @Composable fun CameraPreviewView( nodePublisher: NodePublisher, selectedCamera: Camera = Camera.FRONT, modifier: Modifier = Modifier, ) { AndroidView( factory = { context -> FrameLayout(context).apply { nodePublisher.attachView(this) val cameraId = if (selectedCamera == Camera.FRONT) { NodePublisher.NMC_CAMERA_FRONT } else { NodePublisher.NMC_CAMERA_BACK } nodePublisher.openCamera(cameraId) } }, onRelease = { nodePublisher.detachView() nodePublisher.closeCamera() }, modifier = modifier ) } ``` ### 4.在界面中添加视图 ``` Box( modifier = Modifier.fillMaxSize() ) { // 相机预览视图作为背景层 CameraPreviewView( nodePublisher, selectedCamera = selectedCamera, modifier = Modifier.fillMaxSize() ) ``` ### 5.在页面中创建NodePublisher对象,并通过生命周期来初始化参数 ``` fun LiveViewPage( // Stream settings serverAddress: String = "", streamKey: String = "", // Video source settings selectedCamera: Camera = Camera.FRONT, isFrontCameraMirrored: Boolean = true, selectedResolution: Resolution = Resolution.P720, selectedOrientation: Orientation = Orientation.PORTRAIT, // Video encoding settings selectedEncodingFormat: EncodingFormat = EncodingFormat.H264, selectedH264Profile: H264Profile = H264Profile.MAIN, selectedH265Standard: H265Standard = H265Standard.ENHANCED_RTMP, videoBitrate: Float = 2000f, selectedKeyframeInterval: KeyframeInterval = KeyframeInterval.AUTO, isHardwareEncoding: Boolean = false, // Audio settings selectedAudioFormat: AudioFormat = AudioFormat.AAC, selectedAACProfile: AACProfile = AACProfile.LC, audioBitrate: Float = 128f, selectedAudioChannels: AudioChannels = AudioChannels.STEREO, isNoiseReductionEnabled: Boolean = false ) { val context = LocalContext.current val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() // NodePublisher 实例 val nodePublisher = remember { NodePublisher(context, "") } DisposableEffect(Unit) { val (baseWidth, baseHeight) = when (selectedResolution) { Resolution.P360 -> 640 to 368 Resolution.P480 -> 864 to 480 Resolution.P720 -> 1280 to 720 Resolution.P1080 -> 1920 to 1080 } val (width, height) = if (selectedOrientation == Orientation.PORTRAIT) { baseHeight to baseWidth } else { baseWidth to baseHeight } nodePublisher.setVideoCodecParam( getVideoCodecId(selectedEncodingFormat), getVideoProfile(selectedEncodingFormat, selectedH264Profile), width, height, 30, (videoBitrate * 1024).toInt() ) nodePublisher.setVideoOrientation(getVideoOrientation(selectedOrientation)) nodePublisher.setKeyFrameInterval(selectedKeyframeInterval.ordinal) nodePublisher.setCameraFrontMirror(isFrontCameraMirrored) // Apply audio settings val sampleRate = 48000 val channels = if (selectedAudioChannels == AudioChannels.STEREO) 2 else 1 val audioBitrateBps = (audioBitrate * 1024).toInt() nodePublisher.setAudioCodecParam( getAudioCodecId(selectedAudioFormat), getAudioProfile(selectedAudioFormat, selectedAACProfile), sampleRate, channels, audioBitrateBps ) nodePublisher.setFlvIdExt(selectedH265Standard == H265Standard.EXTENSION_FLV) nodePublisher.setHWAccelEnable(isHardwareEncoding) nodePublisher.setDenoiseEnable(isNoiseReductionEnabled) nodePublisher.setLogLevel(NodePublisher.LOG_LEVEL_DEBUG) nodePublisher.setOnNodePublisherEventListener { pub, event, msg -> streamingState = when (event) { 2000 -> StreamingState.CONNECTING // 开始连接 2001 -> StreamingState.CONNECTED // 连接成功 2002 -> StreamingState.FAILED // 连接失败 2003 -> StreamingState.RECONNECTING // 重新连接 2004 -> StreamingState.DISCONNECTED // 断开连接 2005 -> StreamingState.NETWORK_ERROR // 网络异常 2006 -> StreamingState.TIMEOUT // 网络超时 else -> streamingState } Log.d("QLive.LiveStage", "LiveStagePage: $event $msg, state: $streamingState") } onDispose { nodePublisher.stop() } } ``` ## Demo 源码 [KotlinDemo.zip](https://www.nodemedia.cn/doc/server/index.php?s=/api/attachment/visitFile&sign=37f7213e195fe6a3b392ecd34165abf1 "[KotlinDemo.zip")
嘿,我是小R,需要帮助随时找我哦
QQ客服:281269007
邮件支持
扫码加微信
回到顶部