Skip to content

Commit

Permalink
feat: add getAssetAbsolutePath to support flutter assets. (fix #181)
Browse files Browse the repository at this point in the history
  • Loading branch information
LichKing-2234 committed Dec 2, 2020
1 parent 7d5c6f6 commit b158d7d
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 8 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${safeExtGet('kotlin_version', '1.3.72')}"
implementation "org.jetbrains.kotlin:kotlin-reflect:${safeExtGet('kotlin_version', '1.3.72')}"
implementation "io.agora.rtc:full-sdk:3.1.2"
implementation "io.agora.rtc:full-sdk:3.1.3"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,28 @@ import androidx.annotation.NonNull
import io.agora.rtc.RtcEngine
import io.agora.rtc.base.RtcEngineManager
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.*
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import io.flutter.plugin.platform.PlatformViewRegistry
import java.io.FileNotFoundException
import kotlin.reflect.full.declaredMemberFunctions
import kotlin.reflect.jvm.javaMethod

/** AgoraRtcEnginePlugin */
class AgoraRtcEnginePlugin : FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler {
private var registrar: Registrar? = null
private var binding: FlutterPlugin.FlutterPluginBinding? = null
private lateinit var applicationContext: Context

/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var methodChannel: MethodChannel
private lateinit var eventChannel: EventChannel
private lateinit var applicationContext: Context

private var eventSink: EventChannel.EventSink? = null
private val manager = RtcEngineManager { methodName, data -> emit(methodName, data) }
private val handler = Handler(Looper.getMainLooper())
Expand All @@ -45,8 +47,9 @@ class AgoraRtcEnginePlugin : FlutterPlugin, MethodCallHandler, EventChannel.Stre
@JvmStatic
fun registerWith(registrar: Registrar) {
AgoraRtcEnginePlugin().apply {
initPlugin(registrar.context(), registrar.messenger(), registrar.platformViewRegistry())
this.registrar = registrar
rtcChannelPlugin.initPlugin(registrar.messenger())
initPlugin(registrar.context(), registrar.messenger(), registrar.platformViewRegistry())
}
}
}
Expand All @@ -63,6 +66,7 @@ class AgoraRtcEnginePlugin : FlutterPlugin, MethodCallHandler, EventChannel.Stre
}

override fun onAttachedToEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
this.binding = binding
rtcChannelPlugin.onAttachedToEngine(binding)
initPlugin(binding.applicationContext, binding.binaryMessenger, binding.platformViewRegistry)
}
Expand Down Expand Up @@ -95,6 +99,10 @@ class AgoraRtcEnginePlugin : FlutterPlugin, MethodCallHandler, EventChannel.Stre
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getAssetAbsolutePath") {
getAssetAbsolutePath(call, result)
return
}
manager::class.declaredMemberFunctions.find { it.name == call.method }?.let { function ->
function.javaMethod?.let { method ->
try {
Expand All @@ -114,4 +122,19 @@ class AgoraRtcEnginePlugin : FlutterPlugin, MethodCallHandler, EventChannel.Stre
}
result.notImplemented()
}

private fun getAssetAbsolutePath(call: MethodCall, result: Result) {
call.arguments<String>()?.let {
val assetKey = registrar?.lookupKeyForAsset(it)
?: binding?.flutterAssets?.getAssetFilePathByName(it)
try {
applicationContext.assets.openFd(assetKey!!).close()
result.success("/assets/$assetKey")
} catch (e: Exception) {
result.error(e.javaClass.simpleName, e.message, e.cause)
}
return@getAssetAbsolutePath
}
result.error(IllegalArgumentException::class.simpleName, null, null)
}
}
4 changes: 4 additions & 0 deletions example/lib/config/agora.config.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
/// Get your own App ID at https://dashboard.agora.io/
const appId = YOUR_APP_ID;

/// Please refer to https://docs.agora.io/en/Agora%20Platform/token
const token = YOUR_TOEKN;

const channelId = YOUR_CHANNEL_ID;
const uid = YOUR_UID;
const stringUid = YOUR_STRING_UID;
39 changes: 38 additions & 1 deletion example/lib/examples/basic/join_channel_audio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ class JoinChannelAudio extends StatefulWidget {

class _State extends State<JoinChannelAudio> {
String channelId = config.channelId;
bool isJoined = false, openMicrophone = true, enableSpeakerphone = true;
bool isJoined = false,
openMicrophone = true,
enableSpeakerphone = true,
playEffect = false;
TextEditingController _controller;

@override
Expand Down Expand Up @@ -91,6 +94,36 @@ class _State extends State<JoinChannelAudio> {
});
}

_switchEffect() async {
if (playEffect) {
widget._engine?.stopEffect(1)?.then((value) {
setState(() {
playEffect = false;
});
})?.catchError((err) {
log('stopEffect $err');
});
} else {
widget._engine
?.playEffect(
1,
await RtcEngineExtension.getAssetAbsolutePath(
"assets/Sound_Horizon.mp3"),
-1,
1,
1,
100,
true)
?.then((value) {
setState(() {
playEffect = true;
});
})?.catchError((err) {
log('playEffect $err');
});
}
}

@override
Widget build(BuildContext context) {
return Stack(
Expand Down Expand Up @@ -133,6 +166,10 @@ class _State extends State<JoinChannelAudio> {
onPressed: this._switchSpeakerphone,
child: Text(enableSpeakerphone ? 'Speakerphone' : 'Earpiece'),
),
RaisedButton(
onPressed: this._switchEffect,
child: Text('${playEffect ? 'Stop' : 'Play'} effect'),
),
],
),
)
Expand Down
2 changes: 2 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ flutter:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/Sound_Horizon.mp3

# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
Expand Down
20 changes: 20 additions & 0 deletions ios/Classes/SwiftAgoraRtcEnginePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Flutter
import UIKit

public class SwiftAgoraRtcEnginePlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
private var registrar: FlutterPluginRegistrar?
private var methodChannel: FlutterMethodChannel?
private var eventChannel: FlutterEventChannel?
private var eventSink: FlutterEventSink? = nil
Expand All @@ -16,6 +17,7 @@ public class SwiftAgoraRtcEnginePlugin: NSObject, FlutterPlugin, FlutterStreamHa

public static func register(with registrar: FlutterPluginRegistrar) {
let rtcEnginePlugin = SwiftAgoraRtcEnginePlugin()
rtcEnginePlugin.registrar = registrar
rtcEnginePlugin.rtcChannelPlugin.initPlugin(registrar)
rtcEnginePlugin.initPlugin(registrar)
}
Expand Down Expand Up @@ -61,6 +63,10 @@ public class SwiftAgoraRtcEnginePlugin: NSObject, FlutterPlugin, FlutterStreamHa
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "getAssetAbsolutePath" {
getAssetAbsolutePath(call, result: result)
return
}
if let params = call.arguments as? NSDictionary {
let selector = NSSelectorFromString(call.method + "::")
if manager.responds(to: selector) {
Expand All @@ -76,4 +82,18 @@ public class SwiftAgoraRtcEnginePlugin: NSObject, FlutterPlugin, FlutterStreamHa
}
result(FlutterMethodNotImplemented)
}

private func getAssetAbsolutePath(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if let assetPath = call.arguments as? String {
if let assetKey = registrar?.lookupKey(forAsset: assetPath) {
if let realPath = Bundle.main.path(forResource: assetKey, ofType: nil) {
result(realPath)
return
}
}
result(FlutterError.init(code: "FileNotFoundException", message: nil, details: nil))
return
}
result(FlutterError.init(code: "IllegalArgumentException", message: nil, details: nil))
}
}
1 change: 1 addition & 0 deletions lib/rtc_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export 'src/classes.dart';
export 'src/enums.dart';
export 'src/events.dart' show RtcEngineEventHandler;
export 'src/rtc_engine.dart' show RtcEngine;
export 'src/rtc_engine_extension.dart';
12 changes: 12 additions & 0 deletions lib/src/rtc_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ class RtcChannel with RtcChannelInterface {
}
}

/// @nodoc
mixin RtcChannelInterface
implements
RtcAudioInterface,
Expand Down Expand Up @@ -421,6 +422,7 @@ mixin RtcChannelInterface
Future<String> getCallId();
}

/// @nodoc
mixin RtcAudioInterface {
/// Adjusts the playback volume of a specified remote user.
///
Expand Down Expand Up @@ -463,6 +465,7 @@ mixin RtcAudioInterface {
Future<void> setDefaultMuteAllRemoteAudioStreams(bool muted);
}

/// @nodoc
mixin RtcVideoInterface {
/// Stops/Resumes receiving the video stream of the specified user.
///
Expand All @@ -488,6 +491,7 @@ mixin RtcVideoInterface {
Future<void> setDefaultMuteAllRemoteVideoStreams(bool muted);
}

/// @nodoc
mixin RtcVoicePositionInterface {
/// Sets the sound position of a remote user.
///
Expand All @@ -508,6 +512,7 @@ mixin RtcVoicePositionInterface {
Future<void> setRemoteVoicePosition(int uid, double pan, double gain);
}

/// @nodoc
mixin RtcPublishStreamInterface {
/// Sets the video layout and audio settings for CDN live.
///
Expand Down Expand Up @@ -552,6 +557,7 @@ mixin RtcPublishStreamInterface {
Future<void> removePublishStreamUrl(String url);
}

/// @nodoc
mixin RtcMediaRelayInterface {
/// Starts to relay media streams across channels.
///
Expand Down Expand Up @@ -596,6 +602,7 @@ mixin RtcMediaRelayInterface {
Future<void> stopChannelMediaRelay();
}

/// @nodoc
mixin RtcDualStreamInterface {
/// Sets the video stream type of the remote video stream when the remote user sends dual streams.
///
Expand All @@ -614,6 +621,7 @@ mixin RtcDualStreamInterface {
Future<void> setRemoteDefaultVideoStreamType(VideoStreamType streamType);
}

/// @nodoc
mixin RtcFallbackInterface {
/// Sets the priority of a remote user's media stream.
///
Expand All @@ -628,6 +636,7 @@ mixin RtcFallbackInterface {
Future<void> setRemoteUserPriority(int uid, UserPriority userPriority);
}

/// @nodoc
mixin RtcMediaMetadataInterface {
/// Registers the metadata observer.
///
Expand All @@ -654,6 +663,7 @@ mixin RtcMediaMetadataInterface {
Future<void> sendMetadata(String metadata);
}

/// @nodoc
mixin RtcEncryptionInterface {
/// Enables built-in encryption with an encryption password before joining a channel.
///
Expand Down Expand Up @@ -708,6 +718,7 @@ mixin RtcEncryptionInterface {
Future<void> enableEncryption(bool enabled, EncryptionConfig config);
}

/// @nodoc
mixin RtcInjectStreamInterface {
/// Injects an online media stream to a [ChannelProfile.LiveBroadcasting] channel.
///
Expand Down Expand Up @@ -739,6 +750,7 @@ mixin RtcInjectStreamInterface {
Future<void> removeInjectStreamUrl(String url);
}

/// @nodoc
mixin RtcStreamMessageInterface {
/// Creates a data stream.
///
Expand Down
Loading

0 comments on commit b158d7d

Please sign in to comment.