In this project we are going to build a pared-down version of TikTok. You are going to build an app that allows you to upload URLs of online videos to a database, play those videos, and “like” your favorites.
We will be using the Firebase Realtime Database to store the URLs, “likes”, and viewing information.
Quick demo available on Canvas
There are many steps to this project; I encourage you to start early.
In this step we are going to set up an iOS app and tie it into the database.
assign5
in your repository.
edu.maryland.cmsc436.spring2021.openTok
,
though we will possibly change this later.assign5
as well, create a realtime database, and do not forget to download GoogleService-Info.plist
Podfile
should consist of the following:
```
target ‘openTok’ do # Comment the next line if you don’t want to use dynamic frameworks use_frameworks!
# Pods for openTok pod ‘Firebase/Database’ end
***Important***, to add the firebase configure code to our app, you may find that you do not have a file named `AppDelegate.swift`, instead, you should modify your `assign5App.swift` as:
import SwiftUI import Firebase
@main struct assign5_testApp: App { var body: some Scene { WindowGroup { ContentView() } }
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
} } ```
assign5
directory. Install Cocoapods on your machine if you don’t already
have it. Easiest is to use sudo gem install cocoapods
, but if
you don’t have root access look here
under “Sudo-less Installation”. Then type pod install
on the command line inside your top assign5
directory.
From then on, always open assign5.xcworkspace instead of “assign5.xcodeproj”.Try out your database! Go to https://console.firebase.google.com, create the realtime database if you haven’t already, and then click on ‘Realtime Database’. Click on rules:
Set up both read and write rules as true.
Now go to the data tab. Real-time means that as you insert data from your app, it will magically appear in the browser window (see the demo for an example). Assuming you have correctly set up cocoapods, and the GoogleService-Info.plist
. In your ContentView.swift, you should be able to try the following code:
struct ContentView: View {
func upload() {
FirebaseApp.configure()
let root = Database.database().reference()
root.child("urls").childByAutoId().setValue(["name": "Neo romps happily in the snow", "url": "https://sedna.cs.umd.edu/436clips/vids/neo.mp4"])
}
var body: some View {
Button(action: upload) {"Upload"}
}
}
You should see the following on your firebase console. Remember to import Firebase
and FirebaseDatabase
on top of your file:
You should end up with at least two additional View files, named as UploadView.swift
and PlayerView.swift
(You may name them as you want and create more files if needed). You should create a TabView
in your ContentView, including there two views.
This view controller will just allow the user to input a URL and description (through TextField
s) and insert into
the database. A url and description can be inserted to firebase as follows:
root.child("urls").childByAutoId().setValue(["name": "Meditation Sheep",
"url": "https://sedna.cs.umd.edu/436clips/vids/sheep.mp4"])
Use of the childByAutoID()
guarantees a unique key, even with simultaneous insertions
into the database.
Use an “Upload” button or to affirmatively trigger the database insertion.
Note that you can edit and delete data in the database from the console browser window. Hover the mouse to the right of data and you will see options.
There are many ways to go here. You could, in fact, draw out an AVKit Player View
Controller
, but it does not give you many options to customize. Note that aside from just
playing the videos, we want to display text over the video (the description, number of
likes), a button (“like”), and a gesture recognizer (or two). These are not easily built
on top of the default approach, but be my guest and try.
A slightly easier approach is to use a VideoPlayer
. Using this approach can be as simple as:
VideoPlayer(player: AVPlayer(url: "..."))
What else do we need to do?
Read the URLs from the database by creating an observer (firebase
docs) for the
path “root/urls” (w/ type .value
). This observer is triggered every time data changes,
and happens asynchronously with respect to your app. The snapshot you get from this is not easy to parse, see the Firebase docs for complete information.
You should also imlement a button by clicking which you should be able to download a snapshot of the data.
The firebase upload / download is asynchronized. When you start your app, you may see no video or see the inital video hardcoded set by you since the view is rendered before app fetch the data from firebase.
The following is a snapshot of the database showing four URLS, two likes (only one opened), and also “Seen” information:
“Seen” information is just keeping track of which videos you have seen. This is a binary value, seen or never seen. You will use this information to inform your video sorting heuristic to prefer fresh new videos over those you have seen before.
In addition to writing new URLs to the database as discussed above, you also need to add “like” and “seen” information.
Add the “like” information under “urls/
Add the “seen” information under “seen/
When your app goes live you want people to see videos that others have liked (high “like” count), but also fresh new videos (not in your “seen” data). Given a set of URLs pulled from the database, your sorting algorith should put all unseen videos first (order among them does not matter), and then sort the rest according to descending number of likes.
Through this approach you build a video “playlist”.
However, your URL observer is always running, and may be triggered asynchronously because of new URLs or “likes” from other users. When to rebuild the playlist? There are many ways to go here, but these are my rules of thumb:
With this scheme you can never have more than one like per video, as you only have one directory ID. However, the last stage of this project is going live on the same database as everyone else.
After getting your code running on your own database, you can try running it against our shared database (which is where we will test it).
Please note: There are no permissions, and any one of you can blow away or mess up the entire database. Please be very careful when you start using this live database so as not to annoy all the other users.
Please also note: Uploading any inappropriate URLs will be reported to the proper university officials. There are 150 students in the class, from every conceivable background. This is not the place have fun with NSFW videos, or to argue your political stance. Please report any violations to me; I can track who inserted what into the DB.
Steps:
GoogleService-Info.plist
with the following one:
GoogleService-Info.plist.edu.maryland.cmsc436.spring2020.openTok.<dirid>
. This will
no longer match the bundleID expected by the DB, but in its current permissive mode data
will still be accessible.Need to make sure your phone trusts the developer. When attempting to run on your phone, you may receive a “signature not trusted by phone” or some such (this is not the exact wording). When this happens you can go into Settings / General / Devide Management and explicitly trust your developer signature.
Secondly, you may want to explicitly enable the app to use wireless data (though this might burn through your data plan quickly).
You should have uploaded at least 4 videos to your database before we test your app, with arbitrary value of likes and seen
You may do at most one of these two bonus tasks. Each 15 pts, redeemable on final.