Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Compose Multiplatform で Bluesky のクライアント作ってみた / ...
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Yuki Anzai
April 30, 2023
Technology
790
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Compose Multiplatform で Bluesky のクライアント作ってみた / Bluesky client with Compose Multiplatform
Bluesky/ATProtocol 勉強会#1
https://428lab.connpass.com/event/280610/
Yuki Anzai
April 30, 2023
More Decks by Yuki Anzai
See All by Yuki Anzai
Compose 新機能総まとめ / What's New in Jetpack Compose
yanzm
0
320
StackChan 買いました / I bought my StackChan
yanzm
0
45
Android の公式 Skill / Android skills
yanzm
0
200
Android Studio Otter の最新 Gemini 機能 / Latest Gemini features in Android Studio Otter
yanzm
0
1.2k
Devin で iOS の PR から Android のコードを生成する / Generate Android code from iOS PR using Devin
yanzm
0
280
AI ツールを活用したコードリーディング - Android の公式サンプル Now in Android のソースコードを読んでみよう - / Code reading with AI tools
yanzm
1
700
EncryptedSharedPreferences が deprecated になっちゃった!どうしよう! / Oh no! EncryptedSharedPreferences has been deprecated! What should I do?
yanzm
0
3.2k
Devinを使ったモバイルアプリ開発 / Mobile app development with Devin
yanzm
0
460
Android Studio の 新しいAI機能を試してみよう / Try out the new AI features in Android Studio
yanzm
0
480
Other Decks in Technology
See All in Technology
公式ドキュメントの歩き方etc
coco_se
1
120
伝票作成AIエージェントを支える、LLMOpsとインフラの選択肢 / AICon2026_takeda
rakus_dev
0
140
インフラと開発の垣根を超えていき!〜元AWSインフラエンジニアがAWS開発で奮闘している話〜
hatahata021
3
300
第67回コンピュータビジョン勉強会CVPR2026読会前編
tsukamotokenji
0
150
副作用のある Lambda でも Lambda Power Tuning は使えるのか / lambda-power-tuning-side-effects
koukihosaka
1
120
「顧客の声を聞かなければ何も始まらない」 ── 顧客の声から生まれた『AI返信補助機能』の開発プロセス / AICon2026_shikata_imai
rakus_dev
0
140
Alphaモジュール使っていいのかい!?いけないのかい!?どっちなんだいっ!?
watany
1
290
ゴールデンパスは敷いただけでは道にならない ─ 企画部門のエンジニアが技術標準を事業価値に変えるまで
mhrtech
1
230
ファミコンでPHPを動かす / PHP on the Famicom
tomzoh
2
480
「AIに依存している」と 「AIを使いこなしている」の違い
k8yasuma
0
120
AmplifyHostingConstructからSSRフレームワークのためのホスティング設計を考察する/amplify-hosting-construct
fossamagna
1
250
CIで使うClaude
iwatatomoya
0
290
Featured
See All Featured
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
770
[SF Ruby Conf 2025] Rails X
palkan
2
1.2k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.2k
The Cult of Friendly URLs
andyhume
79
6.9k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
590
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
650
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.6k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
610
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
370
Transcript
$PNQPTF.VMUJQMBUGPSNͰ #MVFTLZͷΫϥΠΞϯτ࡞ͬͯΈͨ yanzm
ZBO[NʢΜ͟Ήʣ w !ZBO[NCTLZTPDJBM w ݹʢ͍ʹ͑͠ʣͷ"OESPJEFS w ݄ʹ,PKJSB͞ΜʹটίʔυΒͬͯCMVFTLZ͡Ί·ͨ͠ɻ৽ถͰ ͢ɻ
,PUMJO w ʢͱͱʣ+7.ݴޠ w CFUUFS+BWBతͳ w ͔Β"OESPJEͷެࣜαϙʔτݴޠͷҰͭ
,PUMJO.VMUJQMBUGPSN ,.1 w ,PUMJOͷίʔυΛXFC +T ͱ͔OBUJWF EFTLUPQ ͱ͔ͷόΠφϦʹϏϧυ w ಉ͡,PUMJOͷίʔυͰෳͷ1MBUGPSNʹରԠ
w J04ରԠ w ͨͩ͠ɺ6*ͦΕͧΕͷ1MBUGPSN/BUJWFͳ෦Ͱ࣮
+FUQBDL$PNQPTF w "OESPJEͷωΠςΟϒ6*Λߏங͢ΔͨΊͷ࠷৽ͷπʔϧΩοτ w એݴత6* Row { Icon( imageVector =
Icons.Default.Star, contentDescription = null ) Column { Text( text = "username" ) Text( text = "description" ) } Button( onClick = onClickFollow ) { Text("follow") } }
$PNQPTFGPS%FTLUPQ w ݄ w +FUQBDL$PNQPTFͰ,PUMJO.VMUJQMBUGPSNͷEFTLUPQͷ6*͕࡞ΕΔ
$PNQPTF.VUMJQMBUGPSN6*'SBNFXPSL w IUUQTXXXKFUCSBJOTDPNMQDPNQPTFNVMUJQMBUGPSN w ݄ͷ,PUMJO$POGͰൃද w EFTLUPQ͚ͩ͡Όͳ͘J04 "MQIB ,PUMJO/BUJWF 8FC
&YQFSJNFOUBM ,PUMJO8BTN αϙʔτ
#MVFTLZͷΫϥΠΞϯτΞϓϦΛ $PNQPTF.VMUJQMBUGPSNͰ࡞Δ https://github.com/yanzm/Rayleigh
4UFQϕʔεͷϓϩδΣΫτΛ࡞Δ w +FU#SBJOTͷHJUIVCʹDPNQPTFNVMUJQMBUGPSNͷςϯϓϨʔτ͕͋Δ w IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFNVMUJQMBUGPSNJPTBOESPJE UFNQMBUF
4UFQ௨৴Ͱ͖ΔΑ͏ʹ͢Δ w 4FJVO͞Μ3FUSP fi UΛ͍͚ͬͯͨͲ,.1Ͱ͑ͳ͍ w ,UPS w IUUQTLUPSJP w
,PUMJO$POG`ͷηογϣϯͰग़͖ͯͨ$PNQPTF.VMUJQMBUGPSNͰνϟο τ͢ΔΞϓϦ͕ࢀߟʹͳͬͨ w IUUQTHJUIVCDPNTWUL,$$IBU"QQ w ,UPS ,PUMJOY4FSJBMJ[BUJPOͱ͔
4UFQϩάΠϯը໘ͷ6*Λ࡞Δ
4UFQϩάΠϯը໘ͷ6*Λ࡞Δ w SEQBSUZDMJFOU"QQ1BTTXPSEͰϩάΠϯ͢ΔΑ͏ʹͳ͔ͬͨΒɺΞΧ ϯτͷ࡞ϩάΠϯ"QQ1BTTXPSEͷ࡞ϒϥβΛ։͍ͯIUUQT TUBHJOHCTLZBQQΛද͍ࣔͨ͠ w "OESPJE J04ͦΕͧΕͷQMBUGPSNͷॲཧ͕ඞཁ
@Composable fun App( onOpenBrowser: (String) -> Unit = {} )
{ RayleighTheme { … LoginScreen( viewModel = viewModel, onOpenBrowser = onOpenBrowser, ) } } shared/commonMain
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContent { MainView( onOpenBrowser = { startActivity( Intent(Intent.ACTION_VIEW, Uri.parse(it)) ) } ) } } @Composable fun MainView( onOpenBrowser: (String) -> Unit ) { App( onOpenBrowser = onOpenBrowser ) } androidApp/ shared/androidMain Android
struct ComposeView: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController {
Main_iosKt.MainViewController( onOpenBrowser: { let url = URL(string:$0)! UIApplication.shared.open(url, options: [:], completionHandler: nil) } ) } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } fun MainViewController( onOpenBrowser: (String) -> Unit ) = ComposeUIViewController { App( onOpenBrowser = onOpenBrowser ) } iosApp/iosApp/ContentView.swift shared/iosMain iOS
4UFQϩάΠϯ͢Δ w "1*Λୟ͍ͯฦ͖ͬͯͨUPLFOΛอଘ͠ͳ͍ͱ͍͚ͳ͍ w NVMUJQMBUGPSNTFUUJOHTΛ͏͜ͱʹ͢Δ w IUUQTHJUIVCDPNSVTTIXPMGNVMUJQMBUGPSNTFUUJOHT w ϓϥοτϑΥʔϜ͝ͱʹ4FUUJOHTͷੜΠϯελϯε͕ҟͳΔ w
%*͕ͳ͍ͱͭΒ͍
4UFQ%FQFOEFODZ*OKFDUJPO w "OESPJEͰEBHHFSIJMU͕σϑΝΫτ͕ͩ,.1Ͱ͑ͳ͍ w ,PJO w LPJODPSF,.1ʹରԠ͍ͯ͠Δ͕ w LPJODPNQPTF$PNQPTF.VMUJQMBUGPSNʹ·ͩରԠ͍ͯ͠ͳ͍ w
l$PVMEOPU fi OEJPJOTFSULPJOLPJODPNQPTFJPTBSNzͱౖΒΕ Δ w IUUQTJOTFSULPJOJPEPDTSFGFSFODFLPJODPNQPTFNVMUJQMBUGPSN 8*1
class AppComponent : KoinComponent { val authRepository: AuthRepository by inject()
} shared/commonMain @Composable fun App( appComponent: AppComponent, onOpenBrowser: (String) -> Unit = {} ) { RayleighTheme { val appViewModel = remember { AppViewModel(appComponent.authRepository) } … } }
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContent { MainView( appComponent = AppComponent(), onOpenBrowser = { startActivity( Intent(Intent.ACTION_VIEW, Uri.parse(it)) ) @Composable fun MainView( appComponent: AppComponent, onOpenBrowser: (String) -> Unit ) { App( appComponent = appComponent, onOpenBrowser = onOpenBrowser ) } androidApp/ shared/androidMain Android
struct ComposeView: UIViewControllerRepresentable { let appComponent = AppComponent() func makeUIViewController(context:
Context) -> UIViewController { Main_iosKt.MainViewController( appComponent: appComponent, onOpenBrowser: { let url = URL(string:$0)! UIApplication.shared.open(url, options: [:], completionHandler: nil) } ) } fun MainViewController( appComponent: AppComponent, onOpenBrowser: (String) -> Unit ) = ComposeUIViewController { App( appComponent = appComponent, onOpenBrowser = onOpenBrowser ) } iosApp/iosApp/ContentView.swift shared/iosMain iOS
4UFQλΠϜϥΠϯΛऔಘ͢Δ w ϩάΠϯ࣌ʹऔಘͨ͠5PLFOΛCFBSFSBVUIFOUJDBUJPOʹηοτ͢Δ w ,UPSͷ"VUIQMVHJO͏͚ͩ w IUUQTLUPSJPEPDTCFBSFSDMJFOUIUNM w UZQFͰΦϒδΣΫτ͕มΘΔ3FDPSEͱ͔$MBTTEJTDSJNJOBUPSGPS QPMZNPSQIJTN͏
w IUUQTHJUIVCDPN,PUMJOLPUMJOYTFSJBMJ[BUJPOCMPCNBTUFSEPDT KTPONEDMBTTEJTDSJNJOBUPSGPSQPMZNPSQIJTN
None
·ͱΊࠓޙ w /BWJHBUJPOͲ͏ͨ͠Β͍͍ͷͩʜ w %FDPNQPTF IUUQTHJUIVCDPNBSLJWBOPW%FDPNQPTF w %*͕ͭΒ͍ʜ
w LPJODPNQPTF͕ରԠͨ͠ΒָʹͳΔ͔ʁ w 5FYU'JFMEͷڍಈ͕J044JNVMBUPSͰ͓͔͍͠ʜ w $PNQPTFͰී௨ʹJ04ͷ6*͕Ͱ͖͍ͯ͢͝ͷͰɺ͍Ζ͍ΖΓ͍ͨ