Adding a Streams API to a Flutter Plugin (The Boring Flutter Development Show, Ep. 7.5)

[BEEP] [THEME MUSIC] ANDREW: So, OK, so we’re back with Dash EMILY: Are we rolling? ANDREW: We’re rolling EMILY: Oh ANDREW: Now we have to restart the introduction [LAUGHTER] EMILY: I’m sorry Hi ANDREW: OK, yeah We’ve gone full pirate EMILY: [CHUCKLE] ANDREW: We’ve gone full pirate with Dash So we’re in here, now, in our Dart interface And we would like to have this be stream-based, because that is more sort of idiomatic to Dart and Flutter, as opposed to just polling it EMILY: Getting a single read in Yeah ANDREW: If it’s for C++, polling something, a value, would make more sense But we have streams in Dart and Flutter And they’re great So we would like to– we can keep all this, that we have, I think We just need a new method for subscribing to a stream And then we’re going to have to, in our Java-land, our Java code, over here, we’re going to have to find a way to kick something out Rather than just setting a thing here, so that we can grab it when we want it, we want to actually kick a value out So we’ll need a methodChannel, so that we can call a method in Dart EMILY: So there’s actually an eventChannel class that allows you to hand a stream-like object to Dart– ANDREW: Really? EMILY: –and then you can do that ANDREW: Is that in the guide that I probably didn’t read all of? EMILY: Yeah That’s part of the– there’s a– [TYPING] If you search– yeah– eventChannel ANDREW: Hold on EMILY: Flutter eventChannel ANDREW: There is– Oh, my goodness EMILY: Docs There we go ANDREW: What? Whoa [LAUGHS] That’s the Java end of it EMILY: It’s all Java! ANDREW: We’re swept in the Java doc style I was like, are we– did we just go to another company? What happened? EMILY: [CHUCKLE] ANDREW: What did we just do? So there’s Java involved That’s– we know that EMILY: Yes ANDREW: The Dart– there we go A namedChannel for– EMILY: Oh, sorry I thought you were looking for the actual Dart version ANDREW: No, I was not I was looking for this I just clicked on the wrong thing Interesting I’ve never had call to use this yet This kind of drives home– we’re talking about how you won’t spend that much time developing plugins, like this, because, normally, the Flutter team is behind a whole bunch of them And the community makes even more This– my embarrassment kind of just drives home that point EMILY: Well, no, I guess it just shows that, yeah, even we’re not writing plugins most of the time ANDREW: Yeah, that is true Well, tell you what, why don’t we switch seats again? And you can– why don’t you show me how it’s done? EMILY: All right Cool ANDREW: OK EMILY: Back on the laptop of coding ANDREW: [CHUCKLE] EMILY: OK, so let’s start with Dart ANDREW: Sure EMILY: So we’re going to– wait Is this our example? No ANDREW: That’s the app That’s the example app EMILY: Oh, OK Let’s– where is our Dart? Here we go OK So we have a methodChannel Let’s also declare a eventChannel Static cost eventChannel [TYPING] ANDREW: How long have you been working with Dart, now, actually? [LAUGHTER] EMILY: I want to say like, not consecutively, but a total of five years ANDREW: Wow OK I feel less bad for not knowing this now, since I’ve been working with Dart for like six months now EMILY: All right OK, so let’s call this– we’ll call it barometer stream, maybe? ANDREW: Pressure stream, maybe? EMILY: Pressure stream ANDREW: That will make us– because we’re just so metal EMILY: Yeah, it sounds so hardcore ANDREW: Yeah EMILY: OK And now– so in our initialize– I think we also need to initialize this Oh, wait ANDREW: Wait, you already initialized it, right there EMILY: Yes ANDREW: Right? EMILY: Yes Sorry OK, so now we need to have our Dart method that returns a stream So just be static stream We want a stream of the– ANDREW: Yeah, doubles would be fine EMILY: –readings And then what do we want to call this? ANDREW: This will be a getter EMILY: Pressure stream ANDREW: Pressure values Pressure– what are you– pressure stream is fine EMILY: OK I think, if I can type– ANDREW: So we have– OK, so we just– we’re defining a getter So that is a little teeny function that will return a stream of doubles And the function, the getter, itself, is that going to be asynchronous or is it going to– EMILY: It’s not Because– yeah, sorry I was in future mode Yeah No, the getter is just returning a stream And the stream will receive updates and make– ANDREW: But I mean, all our other methods are

async too, right? EMILY: Right That’s why I was initially– but then it says that the results, if you have async, the result has to be a future And we don’t want a future, because the stream is going to be getting the– ANDREW: So we don’t want a future of a stream EMILY: Yeah, I guess– ANDREW: We just want the stream EMILY: An Interesting question is, with this invoking method, is that asynchronous? I don’t think so ANDREW: Well, so the other calls are asynchronous, because you have to pass a message into– EMILY: And then it has to do– ANDREW: –the other side But we’re just going to return– I assume the eventChannel, itself, exposes a stream? EMILY: Yeah, but we’re going to have to pass a message to Java to say, give me the stream ANDREW: OK, but– EMILY: I think we should be able to just get away with a stream ANDREW: OK, let’s start And the static analysis will let us know when we’re wrong EMILY: Or failing to get a number, that might work, too OK, so then, Channel– I can type ANDREW: Wait, eventChannel, you mean? EMILY: Thank you You are on top of things here ANDREW: I’m paying attention, because I don’t know what’s going on EMILY: I think– do we just return– no There’s– ANDREW: Receive broadcast stream? EMILY: Yeah Yeah, maybe that ANDREW: I’m just looking for the word “stream.” That’s like a– EMILY: Now, this is going to read– oh, this is not VS code I’m sorry OK, let’s see, eventChannel ANDREW: This is the downside to having official support for so many editors EMILY: OK, so stream, we just returned stream So we just return that ANDREW: OK, perfect EMILY: Great ANDREW: And is that a typed function or are we going to get stream of dynamic? EMILY: Oh, right So, yes And actually– OK, here’s a thing I think we should have a stream variable, and only initialize it once Because we don’t need multiple– if multiple people– or if we subscribe to the stream, we don’t need a separate Java object ANDREW: And it says it’s a broadcast stream, which can handle multiple listeners Right? EMILY: True Yeah So let us declare, make everything static This is great It’s not constant stream, double [TYPING] No, I was going to say pressure stream Yeah, pressure stream OK, and then we’ll say it can return– oh, I’ll just do a click and return pressure stream if not null And then we’re going to do our call, this thing So if– oh wait, we need to sign that ANDREW: I was– OK [TYPING] EMILY: Oops Question equals no Conditions– ANDREW: Is there are double question mark equals? [TYPING] That is cool EMILY: Oh, you didn’t know about that? Oh, yeah That’s a newish feature but, yeah Basically it’s saying, if this is null, do the thing, otherwise, just have the value So now we will return– ANDREW: Interesting EMILY: –pressure stream That should work OK, so now we’ve got all our Dart stuff Do we want to delve into the Java? ANDREW: So that’s– so on the Java side, we’ll have to make– so we have methodChannels on both sides So we would need eventChannels on both sides, too, right? EMILY: Yes ANDREW: All right EMILY: So I think you clicked on– oh, my gosh It’s Java ANDREW: We all find our way eventually EMILY: So– ANDREW: Yeah, let’s– EMILY: Do a little bit of that? ANDREW: Yeah, let’s– you should keep going EMILY: OK All right So in here, we’re going to register our eventChannel Thank you ANDREW: So we’re in the register with method For those of you who saw us last time, we talked about this a little bit This is where– this is called– when the plug-in is first spun up And so this is the, hey, get ready I’m going to make some calls on you And I want some data from you So this is where it registers that methodChannel, so it can receive requests to run methods And then– EMILY: Import it And I’m sure there’s a shortcut for this that I am not– ANDREW: Alt, Enter, yeah EMILY: All right, so there’s that ANDREW: I’m sure there’s one in VS code, too EMILY: Yes, there is ANDREW: But I don’t know I used to use Visual Studio all the time, and then I stopped EMILY: OK, an eventChannel ANDREW: What do we have? EventSink, EndStreamHandler EMILY: So here we have our messenger Oh, it’s basically the same stuff So registrar.messenger and the name of the thing that we want

Yeah, OK And then, OK, so then we want to set this barometer plug-in as the handler for that So I think there is a set something handler or stream handler EventChannel– ANDREW: Set stream handler? EMILY: This one It’s like it’s almost just exactly what I said EventChannel.setStreamHandler, And it’s going to be– ANDREW: This EMILY: –this Now– wait a minute So why did we do a new here instead of– oh, it’s a static OK Do we want the same object? No, probably not, a separate one in case– what I’m saying is do we want– ANDREW: Oh, I see what you’re saying We’re going to want to have– EMILY: Independent, I think so ANDREW: Now I’ve caught up with you Yeah, so you’re going to want to capture the– wait That’s going to give us two separate instances of the plug-in EMILY: That’s what I was just asking ANDREW: Yeah, no What I was going to say is we should capture– EMILY: If anything, we should do the same ANDREW: –pull that into a local variable EMILY: Great ANDREW: And then– yeah No, you had it right to begin with EMILY: OK Login [TYPING] ANDREW: Perfect And then we’re going to need to– EMILY: Oh, wait ANDREW: Do we need an interface that we have to– EMILY: Oh, right Yes Yeah, so stream handler expects stream handler So we’re going to say implements stream handler No? Oh, yes OK So now– all right So to implement stream handler, we must go deeper We have on cancel and on listen And just like any other real stream ANDREW: Just like any other stream when somebody wants to listen, this is where you– OK EMILY: OK So let’s implement those things Now what is it unhappy about here? ANDREW: That’s the API level that I still haven’t fixed EMILY: Oh, OK All right, so– ANDREW: It’s the one line change, that I’m just really busy, you know? EMILY: On cancel– I’m sure there’s– is it Alt, Enter something for it to be like– help me, Andrew What is it? Too late, I’m typing it Arguments And then why is it not– ANDREW: For this I think it’s a Ctrl, I, too EMILY: Oh All right, you need to access, put your public, private things I’m such a Darter ANDREW: Try Ctrl, I and see if that works Boom EMILY: Look at that Good job, IntelliJ or Android Studio ANDREW: That reminds me that we’re missing the override keyword on the others, but don’t worry about it [LAUGHS] And the ones from two weeks ago, but EMILY: OK, great ANDREW: Clearly optional EMILY: So that is– so now we need to implement these We are going to– basically, when we have this stream, that we have initialized somewhere– where did it go? What is this? Oh, it’s API OK So we have our eventChannel Is this the API? OK So we want to tell it, when we listen, that we can start putting readings into this stream ANDREW: So, yeah What are the parameters in on listen So that’s arguments– EMILY: Events ANDREW: –that we, I guess, don’t really care about EMILY: Yeah, because I think we don’t have any arguments, because we just want the– so– ANDREW: And then that’s what we want, so we get this sink that we can put stuff in EMILY: So I guess we need to– I think we need to make an EventSink And this is what we are going to be passing back to Dart ANDREW: Do we– wait, I thought we got one in the signature of the function EMILY: Oh, sorry Oh, on listen Oh, yes OK ANDREW: Oh, phew That’s much easier than making one EMILY: OK So we are going to– we have our eventSink And we need to read from it? No We need to tell it that we have– wait OK Hold on On listen is calling what or is getting called when?

ANDREW: So that gets called when? EMILY: When we are setting it up, set stream handler So we’re saying this plug-in is now listening And so now we’re saying– ANDREW: So we need to keep that, so we can use it, right? EMILY: Yes ANDREW: The eventSink? EMILY: And so ultimately, we’re going to say something ANDREW: That’s what we’re going to do, right? So, OK– so we have– our on listen method means somebody is listening And they give us a thing to send them data So we’ve got to put that somewhere We need like an mEventSink EMILY: Yes ANDREW: Right? EMILY: Right Yeah, so we’re going to take– we’re– yeah OK So we’re going to take this mEventSink, that we’ve got and then make one So mEventSink, We’ll make one [TYPING] ANDREW: There should be an eventSink class That should exist There we go EMILY: What do I do? ANDREW: Oh, it’s Alt, Enter EMILY: Is it functional? ANDREW: Option, sorry, because we’re on a Mac Option and Enter [TYPING] There we go EMILY: No ANDREW: What just happened? EMILY: I did Option, Enter [TYPING] ANDREW: OK, that works EMILY: All right So we have this And we want to– OK, we– I need to backup for a second ANDREW: Sure EMILY: So when– back in our Dart code we’ve got– do-do-do This is our example, this So we’re saying, I would like to get the broadcast stream Don’t we need to– so, OK– and then in here we’re going to create the stream object that we’re passing to Dart, correct? ANDREW: I thought we just got one EMILY: From on listen ANDREW: Oh, sorry We’re– EMILY: Right? ANDREW: I thought you’d switched back to the other Dart file EMILY: Oh, sorry I did I did briefly No, I just want to talk at a high level, like the process of moving things So we’ve got– ANDREW: We’re going to say– on Dart, we’re going to say, give me a stream, from the registrars, the plug-in management system That’s going to go to the Java class and say, hey, somebody wants a stream And it’s going to call on listen, right? EMILY: Yes And so I guess my question is, when on listen is called, we’re putting the events from– where are the events coming in? That’s where I’m unclear ANDREW: Oh, sure because we covered that one in the other episode So that would be in on sensor change EMILY: On sensor change So when on listen comes, we’re constructing this eventSink And are we just putting this mLatestReading into eventSink? ANDREW: I think So it’s giving us the eventSink We would hold it at that point and then use it EMILY: Oh, just– right Add– ANDREW: And then we would use it up here to just dump doubles into EMILY: I see OK, got it ANDREW: I think EMILY: So m– ANDREW: We’ll find out EMILY: Yes So just like this? [TYPING] mSink? ANDREW: Yeah, I think so And then, you can just take that line and move it up to the other one, to where it says mLatestReading Yeah, just success yourself a double EMILY: Aha ANDREW: Event values Oh, or, yeah That’s even better EMILY: Now is there any– ANDREW: We might want to check– EMILY: Should we be adding this typing? ANDREW: We should probably check that it’s not null there, because otherwise, if they haven’t listened yet, we will immediately crash EMILY: Oh, event sent Yeah, OK So if– ANDREW: Were we smart enough to do this with Kyle, then we could just make it a type safe call or a null safe call EMILY: Not equals a null [TYPING] ANDREW: So if we have an eventSink, use it And then on cancel, we can just null out– EMILY: Yeah, mEventSink equals null Gone ANDREW: OK, well that’s cool EMILY: Let’s see ANDREW: See if it builds, the old build test EMILY: Oh, and yeah OK, so we’ve built. We’re going to see if it compiles But then we have to actually, in our example app, use this ANDREW: Actually use the stream, otherwise nothing will ever get called EMILY: So do have your Android simulator open? ANDREW: I do, somewhere EMILY: Yes There it is ANDREW: Hopefully it will not crash or anything OK So, yeah let’s– that’s a good idea Just build it once and make sure everything– EMILY: So you’re not– right now we’re not going to see anything from the stream,

because we haven’t hooked it up in our example app But we’re just making sure that we don’t get horrible runtime errors ANDREW: Incremental changes EMILY: Yes, because we didn’t write a test So this is our test, right now While it’s building, let’s jump over to our example So what we want to do here– ooh ANDREW: Oh, things happened EMILY: Great Initialize barometer No implementation found for initialized barometer? Do we want to– You’ve run this on Android? ANDREW: Mm-hmm EMILY: Do we want to– this seems not related to the code, the changes I was making ANDREW: Yeah, let’s go look at the plug-in, real quick, and just make sure that nothing got wonky So scroll down a little bit Initialize barometer is right there EMILY: Initialize barometer, yeah, that looks good ANDREW: That’s unusual EMILY: This is going well I’m going to stash my changes and then just try and run it ANDREW: Just make sure that it works EMILY: Yeah, make sure it’s not me ANDREW: That would be great if we were actually in a git-repo [LAUGHTER] Sometimes I just make an extra copy of the project for funsies EMILY: Wait, wait, wait, but why don’t you just even clone another copy? ANDREW: I know EMILY: OK OK, well– ANDREW: That one’s on me EMILY: Oh, this is getting exciting ANDREW: Wait, why is it running now? EMILY: I don’t even– oh no, that’s not what I want to do I wanted to clear the console Can you clear this console? ANDREW: Double-click EMILY: Is it the cache? ANDREW: Two-finger click and you can clear EMILY: Clear all, there we go I just wanted to– let’s try again Maybe we can do a full restart No, there’s something going on Yeah And by the way, here’s our pressure ANDREW: Yeah, it’s still in the thousands So that’s there EMILY: I feel like there must be some typo, initialize barometer ANDREW: We could always close Android Studio and clean the project and reopen it, just to be sure EMILY: I really wish this were a git-repo Wait, wait, here’s another thought What if we check out a git-repo and do a diff? ANDREW: That’s true But I don’t know what else– I mean, we literally ran this like 45 minutes ago EMILY: We didn’t– you ran the iOS version ANDREW: No, I ran the Android one, too EMILY: Oh, OK So close this? ANDREW: Mm-hmm, confirm exit EMILY: Confirm Terminate ANDREW: Terminate Then I think you can go into– if you do– No, I mean, right here, in the terminal, I think you can go do– EMILY: Oh, just Flutter run? ANDREW: Just CD example, I think And then do Flutter clean, which I think is a command EMILY: Yes, it is ANDREW: And then we can open Android Studio again EMILY: Oh, I could’ve just run it from the command ANDREW: Oh yeah, you could do that Flutter run– we have a -d Android, probably, because we have it loaded, yeah EMILY: Yeah, -d Is it– ANDREW: Android, It should work, I think The dot, I’m thinking? EMILY: I thought it was like run from the– I guess that just– OK ANDREW: Back before I didn’t know that much about Flutter, and I was working on an AdMob plug-in, I had to do it this way Because I didn’t know any better I had like three editors open, at all times, and four simulators trying to make sure all the little ads showed up where they were supposed to EMILY: [CHUCKLES] ANDREW: You’re killing me, Dart EMILY: OK Initialize barometer Maybe I accidentally deleted something when we were editing Oh, wait, I closed that OK, time to– [TYPING] Android Studio Do we want to call this? ANDREW: Yeah, we might have to EMILY: They’re yanking us off the– ANDREW: Yeah, if this were a “Looney Tunes” cartoon, the big hook would be coming for us

OK You want to comment out the eventChannel stuff, just see what’s– EMILY: Sure ANDREW: We had to have made a mistake– I assume– in there somewhere EMILY: I feel like, rather than that, I suspect I accidentally deleted something when I was typing, somehow selected something Because let’s see here, initialize barometer Let’s remove our eventChannel This is so sad ANDREW: Somebody’s going to put a comment on this and tell us that it’s just in another tab It’s like the barometer pressure sensor on the simulator EMILY: Do I hide– oh, this thing ANDREW: And comment those, as well Is there– scroll up a little bit EMILY: I feel so unsafe developing not in a git-repo ANDREW: I know EMILY: And take this out OK Yeah? ANDREW: You can still go, because we have this code on GitHub And it is possible to go look at what it was before today started So that’s possible EMILY: Yeah, that’s what I was saying is pull down a separate repo and diff ANDREW: Oh, so you suggested the exact thing, and then I just repeated your idea like two minutes later? EMILY: That’s OK It’s OK ANDREW: Takes me a while sometimes EMILY: [CHUCKLES] You were debugging in your head ANDREW: Yeah, I was EMILY: OK, so it is something ANDREW: Wait, wait No EMILY: It is something that I added What the heck? That is– ANDREW: That is cray-cray EMILY: OK, so let us add back the Java ANDREW: Oh, wait Those aren’t supposed to have the same name, are they? EMILY: Oh, my god ANDREW: That should be pressure stream That’s what it is I remember thinking, when you were in Dart, to look for that And I didn’t think to look, here, when we switched over But that’s overwriting the string So somewhere– EMILY: It says the type is– ANDREW: –somewhere in the registrar, there’s a giant map, I assume, of string to channel EMILY: Good catch ANDREW: OK So we’ll uncomment everything, immediate success EMILY: And everything is going to work Yeah ANDREW: We’ll go bake a cake Puppies will appear EMILY: Dash will– ANDREW: Dash will fly off into the night EMILY: Into the low pressure OK, wait What did we import here or implement? ANDREW: Events something? Stream handler, was that it? No EMILY: Where did this go? Where did this go? Barometer plug-in? Yeah, so this, set stream handler ANDREW: Oh, it must be stream handler [TYPING] EMILY: I thought it was– oh, there we go OK I was going to say, I thought there was a little more to it ANDREW: And then that, I think that needs to be uncommented EMILY: Thank you ANDREW: No problem As I continue my rampant backseat coding EMILY: Hey, clearly making mistakes here So– ANDREW: That’s OK [TYPING] EMILY: OK So now– phew– so now, lastly, before the hook really pulls me off stage, let’s add a little into our example app And then we’ll be good So this is our mean And so we want– let us– how about we just– is this the state? ANDREW: Do you want to just throw a stream builder on it? EMILY: Yeah ANDREW: Just like below everything else, just like, and a stream builder, or something like that? EMILY: OK Or, I was just going to– yeah, OK Great ANDREW: If you had a better idea, go for it Don’t let me stop you EMILY: No, let’s do that So we have this column This is going to be beautiful, so we’re going to have raised and then stream builder And then stream is– what did we call everything? Is it barometer dot– where are you even calling this? ANDREW: Barometer.pressureStream? [TYPING] Is it underscore barometer? I’m not seeing where it says defined

ANDREW: Did it get commented out in the barometer? EMILY: Barometer is here Where are we calling our– oh, capital Barometer ANDREW: Oh EMILY: Woo OK, and then– ANDREW: That one I definitely should have remembered It’s not– EMILY: Oh, my gosh ANDREW: It’s context and async snapshot of double, I think I only know that, because I’ve been doing a lot of stuff with streams, recently EMILY: And this is where VS code has a little– you need to say type exactly– ANDREW: Oh, really? EMILY: Yeah ANDREW: I wonder if there’s– EMILY: This is why I love– ANDREW: OK, if anybody knows how to make that just populate EMILY: It’s probably Command, I. It’s probably like Alt, I ANDREW: Yeah EMILY: But anyway ANDREW: Maybe one of the commenters that’s still with us can let us know Because I often request features of the IntelliJ plug-in team And they’re like, yeah, we already have that You just don’t know the keystrokes EMILY: Yes, I do– yes I feel like IntelliJ has a lot of things You just need to know where they are ANDREW: Yeah EMILY: OK, so now we are going to– if snapshot dot– ooh, that was not– ANDREW: Is that not what you were looking for there? EMILY: Snapshot.hasData Let’s see– return text pressure stream, snapshot.data And then we’ll say no data, because, apparently, it’s the 1980s again ANDREW: Yeah, sure All right Is that– so we probably need to rebuild the whole thing EMILY: Well, actually– oh, wait Because it– oh ANDREW: See, that’s not going to rebuild the Java, right? EMILY: Oh, yeah Let’s just kill all this OK Back to full Android Studio mode But there’s going to be a type error Let’s see, what was it complaining about? Well, I guess we’ll find out shortly Oh, wait Oh, no OK, never mind No, I was just thinking– ANDREW: No, there we go EMILY: OK, broadcast stream dynamic is not subtype of the type stream double So I think we need to do a little typing, because I– pressure stream– ANDREW: Oh, wait Where’s the method where you get the as broadcast or receive broadcast stream? EMILY: On Java? ANDREW: Yeah EMILY: That’s why I was asking if we need to– ANDREW: Oh no, in the Dart, in barometer.dart I remember wondering if I– EMILY: Oh ANDREW: So there’s add– can you Command click on receive broadcast stream? Does that have a type parameter on it? EMILY: Should be dynamic ANDREW: No, it does not OK EMILY: So do we need to do a cast like dot as? ANDREW: Do a dot map? EMILY: Or dot map, probably ANDREW: Yeah, map would be the thing to do I think EMILY: OK, so goodbye little fancy thing here If pressure stream equals null [TYPING] So, well, I guess we can do this all on one line, but whatever So we take– we’re going to map our value and map to double ANDREW: Yeah, I think that’s the– EMILY: values ANDREW: –that’s the bidness EMILY: Right And then we’ll just assign that to pressure stream [TYPING] OK [GASP] OK And now we can use this Let’s see, moment of truth here ANDREW: Oh, my god Flutter victory [LAUGHTER] We rule air pressure EMILY: You are now ready to use this app to help you measure your air pressure ANDREW: Yeah, we’re ready for the hot air balloon now EMILY: Fly high ANDREW: Yeah Awesome, OK EMILY: Do we declare victory while we’re ahead? ANDREW: So let’s– yeah, we definitely need to declare victory and get out of here Let’s talk about everything we just did EMILY: Oh, yes ANDREW: So we came in and– EMILY: We added– ANDREW: –there was a desk And we sat down EMILY: We added an iOS app using good old Objective-C Then we attempted to publish the package And we ran into an error, which we are going to look into and get back with you Or someone is going to be like, you forgot a semicolon ANDREW: Yeah, someone will tell us where EMILY: And then we streamified the Java version I think that the last step– well, there’s two last steps– would be to streamify the iOS version ANDREW: So we still need to do that, which we might We might just go on in a couple of weeks

But we should Hopefully, one or both of us will have time to finish this up and get it up on GitHub in a finished state Maybe Dash can do that EMILY: Yes, she’s good at getting code done And then just, yeah, a little cleanup, maybe actually adding a test ANDREW: Yeah, we talked about methodChannels versus eventChannels, which I learned about, having not known about them Cool All right I think that’s about it EMILY: If you’re still here, you should win a prize ANDREW: There you go All right, guys We’ll see you in a couple of weeks Hope you enjoyed it EMILY: Bye [MUSIC PLAYING]