Sessions API با تکیه بر Device Discovery و Secure Connection API یک انتزاع قدرتمند برای ایجاد تجربیات یکپارچه بین دستگاهی ارائه می دهد. یک جلسه نشان دهنده یک تجربه کاربری برنامه است که می تواند بین دستگاه ها منتقل و به اشتراک گذاشته شود.
Sessions API همچنین بر اساس مفهوم تجربیات شخصی و اشتراکی ساخته شده است که به ترتیب با استفاده از انتقال جلسه و موارد استفاده اشتراک جلسه ارائه می شوند. نمودار زیر جلسات را در سطح بالایی نشان می دهد:
ایجاد و انتقال یک جلسه
Sessions API بین دستگاه مبدأ و دستگاه دریافت کننده تفاوت قائل می شود. دستگاه مبدأ جلسه را ایجاد می کند و دستگاهی را جستجو می کند که بتواند جلسه را مدیریت کند. کاربر دستگاه مبدأ یک دستگاه را از لیست ارائه شده توسط گفتگوی سیستم انتخاب می کند. هنگامی که کاربر دستگاه دریافت کننده را انتخاب کرد، جلسه مبدا منتقل شده و از دستگاه مبدأ حذف می شود.
برای انتقال جلسه، ابتدا باید آن را با استفاده از پارامترهای زیر ایجاد کنید:
- یک برچسب جلسه برنامه - یک شناسه که به شما امکان می دهد بین چندین جلسه در برنامه خود تفاوت قائل شوید.
سپس انتقال را با استفاده از پارامترهای زیر آغاز کنید:
- یک
DeviceFilter
برای فیلتر کردن دستگاههایی که قادر به مدیریت جلسه هستند - یک شیء برگشتی که
OriginatingSessionStateCallback
را پیاده سازی می کند
در دستگاه مبدأ، با استفاده از مثال زیر یک جلسه ایجاد کنید:
کاتلین
private val HELLO_WORLD_TRANSFER_ACTION = "hello_world_transfer" private lateinit var originatingSession: OriginatingSession private lateinit var sessions: Sessions override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sessions = Sessions.create(context = this) } suspend fun transferSession() { val sessionId = sessions.createSession( ApplicationSessionTag("hello_world_transfer"), ) originatingSession = sessions.transferSession( sessionId, StartComponentRequest.Builder() .setAction(HELLO_WORLD_TRANSFER_ACTION) .setReason("Transfer reason here") .build(), emptyList(), HelloWorldTransferSessionStateCallback() ) }
جاوا
private static final String HELLO_WORLD_TRANSFER_ACTION = "hello_world_transfer"; private OriginatingSession originatingSession; private Sessions sessions; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); sessions = Sessions.create(/* context= */ this); } public void transferSession() { SessionId sessionId = sessions.createSession(new ApplicationSessionTag("hello_world_transfer")); ListenableFuture<OriginatingSession> originatingSessionFuture = sessions.transferSessionFuture( sessionId, new StartComponentRequest.Builder() .setAction(HELLO_WORLD_TRANSFER_ACTION) .setReason("Transfer reason here") .build(), Collections.emptyList(), new HelloWorldTransferSessionStateCallback()); Futures.addCallback( originatingSessionFuture, new FutureCallback<>() { @Override public void onSuccess(OriginatingSession result) { // Do nothing, handled in HelloWorldTransferSessionStateCallback originatingSession = result; } @Override public void onFailure(Throwable t) { Log.d(TAG, "onFailure called for transferSessionFuture", t); } }, mainExecutor); }
سپس، پاسخ تماس جلسه را در دستگاه مبدأ تعریف کنید:
کاتلین
private inner class HelloWorldTransferSessionStateCallback : OriginatingSessionStateCallback { override fun onConnected(sessionId: SessionId) { val startupRemoteConnection = originatingSession.getStartupRemoteConnection() lifecycleScope.launchWhenResumed { startupRemoteConnection.send("hello, world".toByteArray(UTF_8)) startupRemoteConnection.registerReceiver( object : SessionConnectionReceiver { override fun onMessageReceived(participant: SessionParticipant, payload: ByteArray) { val ok = payload.contentEquals("ok".toByteArray(UTF_8)) Log.d(TAG, "Session transfer initialized. ok=$ok") } } ) } } override fun onSessionTransferred(sessionId: SessionId) { Log.d(TAG, "Transfer done.") } override fun onTransferFailure(sessionId: SessionId, exception: SessionException) { // Handle error } }
جاوا
private class HelloWorldTransferSessionStateCallback implements OriginatingSessionStateCallback { @Override public void onConnected(SessionId sessionId) { SessionRemoteConnection startupRemoteConnection = originatingSession.getStartupRemoteConnection(); Futures.addCallback( startupRemoteConnection.sendFuture("hello, world".getBytes()), new FutureCallback<>() { @Override public void onSuccess(Void result) { Log.d(TAG, "Successfully sent initialization message"); } @Override public void onFailure(Throwable t) { Log.d(TAG, "Failed to send initialization message", t); } }, mainExecutor); } @Override public void onSessionTransferred(SessionId sessionId) { Log.d(TAG, "Transfer done."); } @Override public void onTransferFailure(SessionId sessionId, SessionException exception) { // Handle error } }
هنگامی که انتقال جلسه آغاز شد، دستگاه دریافت کننده یک تماس پاسخ به روش onNewIntent(intent: Intent)
دریافت می کند. دادههای intent شامل همه چیزهایی هستند که برای انتقال جلسه لازم است.
برای تکمیل انتقال در دستگاه گیرنده:
کاتلین
private lateinit var sessions: Sessions override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sessions = Sessions.create(context = this) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) lifecycleScope.launchWhenResumed { val receivingSession = sessions.getReceivingSession(intent, HelloWorldReceivingSessionStateCallback()) // Get info from receiving device and init. val startupRemoteConnection = receivingSession.getStartupRemoteConnection() startupRemoteConnection.registerReceiver( object : SessionConnectionReceiver { override fun onMessageReceived(participant: SessionParticipant, payload: ByteArray) { lifecycleScope.launchWhenResumed { val transferInfo = String(payload) startupRemoteConnection.send("ok".toByteArray(UTF_8)) // Complete transfer. Log.d(TAG, "Transfer info: " + transferInfo) receivingSession.onComplete() } } } ) } } private inner class HelloWorldReceivingSessionStateCallback : ReceivingSessionStateCallback { override fun onTransferFailure(sessionId: SessionId, exception: SessionException) { // Handle error } }
جاوا
private Sessions sessions; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); sessions = Sessions.create(/* context= */ this); } @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); ListenableFuture<ReceivingSession> receivingSessionFuture = sessions.getReceivingSessionFuture(intent, new HelloWorldReceivingSessionStateCallback()); ListenableFuture<Void> registerReceiverFuture = Futures.transform( receivingSessionFuture, receivingSession -> { SessionRemoteConnection startupRemoteConnection = receivingSession.getStartupRemoteConnection(); SessionConnectionReceiver receiver = (participant, payload) -> { Log.d( TAG, "Successfully received initialization message of size: " + payload.length); applicationInitialization(receivingSession, payload); }; startupRemoteConnection.registerReceiver(receiver); return null; }, mainExecutor); Futures.addCallback( registerReceiverFuture, new FutureCallback<Void>() { @Override public void onSuccess(Void unused) { Log.d(TAG, "Connection receiver registerd successfully"); } @Override public void onFailure(Throwable t) { Log.w(TAG, "Failed to register connection receiver", t); } }, mainExecutor); } private void applicationInitialization(ReceivingSession receivingSession, byte[] initMessage) { ListenableFuture<SessionId> disconnectFuture = Futures.transform( receivingSession.onCompleteFuture(), sessionId -> { Log.d(TAG, "Succeeded to complete receive transfer for: " + sessionId); return sessionId; }, mainExecutor); Futures.addCallback( disconnectFuture, new FutureCallback<SessionId>() { @Override public void onSuccess(SessionId result) { Log.d(TAG, "Succeeded to remove the old session: " + result); } @Override public void onFailure(Throwable t) { Log.d(TAG, "Failed to remove the old session, which is now orphaned", t); } }, mainExecutor); } private static class HelloWorldReceivingSessionStateCallback implements ReceivingSessionStateCallback { @Override public void onTransferFailure(SessionId sessionId, SessionException exception) { // Handle error } }
اکنون دستگاه دریافت کننده می تواند با تجربه کاربری ادامه دهد.
یک جلسه را به اشتراک بگذارید
با اشتراک گذاری یک جلسه، می توانید از اطرافیان خود دعوت کنید تا در یک تجربه گروهی شرکت کنند، به عنوان مثال:
- مکان نقشه را به عنوان مسافر مستقیماً با ماشین دوست خود به اشتراک بگذارید.
- مسیر دوچرخه سواری یکشنبه خود را با دیگرانی که با آنها دوچرخه سواری می کنید به اشتراک بگذارید.
- اقلامی را برای سفارش گروهی غذا جمع آوری کنید بدون اینکه گوشی خود را به اطراف بفرستید.
- برای نمایش تلویزیونی بعدی یک رای گروهی بگیرید تا با هم تماشا کنید.
هنگامی که کاربر انتخاب می کند جلسه ای را با دستگاه دیگری به اشتراک بگذارد، دستگاه مبدأ دستگاه هایی را جستجو می کند که قادر به پیوستن به جلسه هستند و کاربر دستگاه(های) گیرنده را انتخاب می کند. برنامه از کاربر در دستگاه دریافت کننده می خواهد تا از دستگاه مبدأ به جلسه ملحق شود. سپس به یک دستگاه دریافت کننده یک جلسه ثانویه داده می شود تا با جلسه دستگاه مبدا تعامل کند. برنامه ها همچنین می توانند شرکت کنندگان بیشتری را به جلسه مشترک جاری خود اضافه کنند.
فرآیند اشتراکگذاری جلسه مشابه انتقال جلسه است، اما به جای فراخوانی transferSession
، shareSession
را فراخوانی کنید. تفاوتهای دیگر در روشهای پاسخ به تماس وضعیت جلسه است.
کاتلین
// Originating side. private val HELLO_WORLD_SHARE_ACTION = "hello_world_share" private var activePrimarySession: PrimarySession? = null private lateinit var sessions: Sessions override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sessions = Sessions.create(context = this) } suspend fun shareSession() { val sessionId = sessions.createSession(ApplicationSessionTag("hello_world_share")) activePrimarySession = sessions.shareSession( sessionId, StartComponentRequest.Builder() .setAction(HELLO_WORLD_SHARE_ACTION) .setReason("Share reason here") .build(), emptyList(), HelloWorldShareSessionStateCallback(), ) } private inner class HelloWorldShareSessionStateCallback : PrimarySessionStateCallback { override fun onShareInitiated(sessionId: SessionId, numPotentialParticipants: Int) { // Custom logic here for when n devices can potentially join. // e.g. if there were 0, cancel/error if desired, // if non-0 maybe spin until numPotentialParticipants join etc. } override fun onParticipantJoined(sessionId: SessionId, participant: SessionParticipant) { // Custom join logic here lifecycleScope.launchWhenResumed { // Example logic: send only to the participant who just joined. val connection = checkNotNull(activePrimarySession).getSecondaryRemoteConnectionForParticipant(participant) connection.send("Initing hello, world.".toByteArray(UTF_8)) connection.registerReceiver( object : SessionConnectionReceiver { override fun onMessageReceived(participant: SessionParticipant, payload: ByteArray) { val ok = payload.contentEquals("ok".toByteArray(UTF_8)) Log.d(TAG, "Session share initialized. ok=$ok") // Example logic: broadcast to all participants, including the one // that just joined. lifecycleScope.launchWhenResumed { checkNotNull(activePrimarySession) .broadcastToSecondaries("hello, all.".toByteArray(UTF_8)) } } } ) } } override fun onParticipantDeparted(sessionId: SessionId, participant: SessionParticipant) { // Custom leave logic here. } override fun onPrimarySessionCleanup(sessionId: SessionId) { // Custom cleanup logic here. activePrimarySession = null } override fun onShareFailureWithParticipant( sessionId: SessionId, exception: SessionException, participant: SessionParticipant ) { // Handle error } }
جاوا
// Originating side private static final String HELLO_WORLD_SHARE_ACTION = "hello_world_share"; @Nullable private PrimarySession activePrimarySession = null; private Sessions sessions; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); sessions = Sessions.create(/* context= */ this); } private void shareSession() { SessionId sessionId = sessions.createSession(new ApplicationSessionTag("hello_world_share")); ListenableFuture<PrimarySession> shareSessionFuture = sessions.shareSessionFuture( sessionId, new StartComponentRequest.Builder() .setAction(HELLO_WORLD_SHARE_ACTION) .setReason("Share reason here") .build(), Collections.emptyList(), new HelloWorldShareSessionStateCallback()); Futures.addCallback( shareSessionFuture, new FutureCallback<PrimarySession>() { @Override public void onSuccess(PrimarySession primarySession) { activePrimarySession = primarySession; } @Override public void onFailure(Throwable t) { Log.d(TAG, "Failed to share session", t); } }, mainExecutor); } private class HelloWorldShareSessionStateCallback implements PrimarySessionStateCallback { @Override public void onShareInitiated(SessionId sessionId, int numPotentialParticipants) { // Custom logic here for when n devices can potentially join. // e.g. if there were 0, cancel/error if desired, // if non-0 maybe spin until numPotentialParticipants join etc. } @Override public void onParticipantJoined(SessionId sessionId, SessionParticipant participant) { PrimarySession joinedSession = activePrimarySession; if (joinedSession == null) { return; } SessionRemoteConnection connection = joinedSession.getSecondaryRemoteConnectionForParticipant(participant); Futures.addCallback( connection.sendFuture("Initiating hello, world.".getBytes()), new FutureCallback<Void>() { @Override public void onSuccess(Void result) { // Send successful. } @Override public void onFailure(Throwable t) { // Failed to send. } }, mainExecutor); connection.registerReceiver( new SessionConnectionReceiver() { @Override public void onMessageReceived(SessionParticipant participant, byte[] payload) { boolean ok = new String(payload, UTF_8).equals("ok"); Log.d(TAG, "Session share initialized. ok=" + ok); // Example logic: broadcast to all participants, including the one // that just joined. Futures.addCallback( joinedSession.broadcastToSecondariesFuture("hello, all.".getBytes()), new FutureCallback<Void>() { @Override public void onSuccess(Void result) { // Broadcast successful. } @Override public void onFailure(Throwable t) { // Failed to broadcast hello world. } }, mainExecutor); } }); } @Override public void onParticipantDeparted(SessionId sessionId, SessionParticipant participant) { // Custom leave logic here. } @Override public void onPrimarySessionCleanup(SessionId sessionId) { // Custom cleanup logic here. activePrimarySession = null; } @Override public void onShareFailureWithParticipant( SessionId sessionId, SessionException exception, SessionParticipant participant) { // Custom error handling logic here. } }
در سمت دریافت کننده:
کاتلین
// Receiving side. override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) lifecycleScope.launchWhenResumed { val secondarySession = sessions.getSecondarySession(intent, HelloWorldSecondaryShareSessionStateCallback()) val remoteConnection = secondarySession.getDefaultRemoteConnection() remoteConnection.registerReceiver( object : SessionConnectionReceiver { override fun onMessageReceived(participant: SessionParticipant, payload: ByteArray) { Log.d(TAG, "Payload received: ${String(payload)}") } } ) } } private inner class HelloWorldSecondaryShareSessionStateCallback : SecondarySessionStateCallback { override fun onSecondarySessionCleanup(sessionId: SessionId) { // Custom cleanup logic here. } }
جاوا
// Receiving side. @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); sessions = Sessions.create(this); ListenableFuture<SecondarySession> secondarySessionFuture = sessions.getSecondarySessionFuture( intent, new HelloWorldSecondaryShareSessionStateCallback()); Futures.addCallback( secondarySessionFuture, new FutureCallback<SecondarySession>() { @Override public void onSuccess(SecondarySession secondarySession) { SessionRemoteConnection remoteConnection = secondarySession.getDefaultRemoteConnection(); remoteConnection.registerReceiver( new SessionConnectionReceiver() { @Override public void onMessageReceived(SessionParticipant participant, byte[] payload) { Log.d(TAG, "Payload received: " + new String(payload, UTF_8)); } }); } @Override public void onFailure(Throwable t) { // Handle error. } }, mainExecutor); } private static class HelloWorldSecondaryShareSessionStateCallback implements SecondarySessionStateCallback { @Override public void onSecondarySessionCleanup(SessionId sessionId) { // Custom cleanup logic here. } }