Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android vs iOS: A 100% fully serious comparison by Jie Li and Sam Jarman

Sam Jarman
September 07, 2018

Android vs iOS: A 100% fully serious comparison by Jie Li and Sam Jarman

A lot of us like to argue about the merits of iOS vs Android, but after a few years in both, Sam and Jie thought they’re more alike than a lot of people think. In this talk, they’ll walk you through some key concepts of both, pointing out the good parts and the bad parts, but really showing you how similar they are.

This comparison is fully serious, and all information will be presented in a completely unbiased and stern way with no smiles on faces. We’ll cover everything from Xcode/Android Studio through to Networking libraries, data storage and unit testing.

Sam Jarman

September 07, 2018
Tweet

More Decks by Sam Jarman

Other Decks in Technology

Transcript

  1. var myVariable = 42 myVariable = 50 val myConstant =

    42 let explicitDouble: Double = 70 Swift Kotlin var myVariable = 42 myVariable = 50 let myConstant = 42 let explicitDouble: Double = 70.0
  2. class Shape { var numberOfSides = 0 fun simpleDescription(): String

    { return "A shape with $numberOfSides sides." } } Swift Kotlin class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
  3. val shoppingList = arrayOf("catfish", "water", "tulips", "blue paint") shoppingList[1] =

    "bottle of water" Swift Kotlin var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water"
  4. Networking - Retrofit public interface GitHubService { @GET("users/{user}/repos" ) Call<List<Repo>>

    listRepos(@Path("user") String user); } Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/ ") .build(); GitHubService service = retrofit.create(GitHubService.class); Call<List<Repo>> repos = service.listRepos("jie"); call.enqueue(new Callback<List<Repo>>() {...})
  5. Networking let urlString = URL(string: "http://jsonplaceholder.typicode.com/users/1") if let url =

    urlString { let task = URLSession.shared.dataTask(with: url) { (data, response, error) in if error != nil { print(error) } else { if let usableData = data { print(usableData) //JSONSerialization } } } task.resume()
  6. Simple Data Storage How can we save light weight data

    such as preferences, high scores or settings
  7. UserDefaults let myData = 5.4 UserDefaults.standard.set(myData, forKey: "myData") // Another

    point in your app let myDataOut = UserDefaults.standard.float(forKey: "myData") print(myDataOut) // 5.4
  8. Room @Entity public class User { @PrimaryKey private int uid;

    @ColumnInfo(name = "first_name") private String firstName; } @Dao public interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Insert void insertAll(User... users); } @Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
  9. Broadcasts - receiving <receiver android:name=".MyBroadcastReceiver" android:exported="true"> <intent-filter> <action android:name="com.example.broadcast.MY_NOTIFICATION"/> </intent-filter>

    </receiver> IntentFilter filter = new IntentFilter("com.example.broadcast.MY_NOTIFICATION"); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); this.registerReceiver(myBroadcastReceiver, filter); public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ... } }
  10. @Test fun testAdder() { // Setup val a = 10

    val b = 15 // Run val result = Adder.add(a, b) // Verify assertEquals(result, 15) } Unit Testing - XCTest Unit Testing - JUnit func testAdder() { // Setup let a = 10 let b = 15 // Run let result = Adder.add(a, b) // Verify XCTAssertEqual(result, 15) }
  11. java.lang.RuntimeException: Method startActivity in android.app.Activity not mocked. See http://g.co/androidstudio/not-mocked for

    details. func testLogin() { // Mock Activity } Unit Testing - JUnit func testLogin() { // Mock server // Mock Disk // Mock user defaults // Instantiate controller properly // Give up? } java.lang.RuntimeException: Method makeText in android.widget.Toast not mocked. See http://g.co/androidstudio/not-mocked for details. func testLogin() { // Mock Activity // Mock Toast } Unit Testing - XCTest
  12. UI Testing - XCUITest let accountSuccessfullyCreatedMessage = self.app.staticTexts["Account successfully created!"]

    let exists = NSPredicate(format: "exists == true") expectation(for: exists, evaluatedWithObject: accountSuccessfullyCreatedMessage, handler: nil) app.buttons["Create Button"].tap() waitForExpectations(timeout: 10, handler: nil) XCTAssert(accountSuccessfullyCreatedMessage.exists) XCTAssert(accountSuccessfullyCreatedMessage.label, "Account successfully created!")
  13. UITesting - AndroidJUnitRunner / Espresso @Test fun testClickMyView() { onView(withId(R.id.my_view))

    // withId(R.id.my_view) is a ViewMatcher .perform(click()) // click() is a ViewAction .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion} } } @RunWith(AndroidJUnit4::class) class SimpleIntentTest { @Rule var mIntentsRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
  14. Dependency Injection class Foo { private let myDependency: MyDependency init(dep:

    MyDependency = MyDependency()) { self.myDependency = dep } func doThing() { myDependency.doOtherThing() } } // Testing Foo let mockDep = MyMockDependencyWhichIsASubclassOfMyDependency() let f = Foo(dep: mockDep) f.doThing()
  15. Dependency Injection - Dagger @Module class DripCoffeeModule { @Provides static

    Heater provideHeater() { return new ElectricHeater(); } @Provides static Pump providePump(Thermosiphon pump) { return pump; } } @Component(modules = DripCoffeeModule.class) interface CoffeeShop { CoffeeMaker maker(); } CoffeeShop coffeeShop = DaggerCoffeeShop.builder() .dripCoffeeModule(new DripCoffeeModule()) .build(); class Thermosiphon implements Pump { private final Heater heater; @Inject Thermosiphon(Heater heater) { this.heater = heater; } ... } class CoffeeMaker { @Inject Heater heater; @Inject Pump pump; ... }
  16. Flavours/Build-Types apply plugin: 'com.android.application' android { buildTypes { release {

    minifyEnabled true proguardFiles ... } debug { minifyEnabled false } } productFlavors { cinnamon { applicationIdSuffix ".cinnamon" versionNameSuffix "-cinnamon" } vanilla { applicationIdSuffix ".vanilla" versionNameSuffix "-vanilla" } } }
  17. Code Signing How can we prove to the Apple and

    Google that it’s our code?
  18. The App Store 1. Archive code 2. Upload to store

    3. Fill in details 4. Submit for review 5. Pray to Tim Cook for no rejection
  19. Lol. @available? if #available(iOS 9.0, *) { print("iOS 9.0 and

    greater") let (contact, imageData) = PersonPopulator.generateContactInfo() profileImageView.image = UIImage(data: imageData) titleLabel.text = contact.jobTitle nameLabel.text = "\(contact.givenName) \(contact.familyName)" } else { print("Get a new phone, m8!) }