evilfactorylabs

Cover image for Segala hal yang saya pelajari dalam membuat aplikasi iOS dari nol
Rizaldy
Rizaldy

Posted on

Segala hal yang saya pelajari dalam membuat aplikasi iOS dari nol

First thing first, disclaimer: saya menulis kode secara "profesional" sudah ~8 tahun dan berurusan dengan program komputer 10+ tahun. Informasi ini mungkin penting untuk menghindari bias khususnya untuk maksud "nol" di bagian judul untuk tulisan ini.

Pertama kali saya belajar iOS development mungkin sekitar tahun 2017, tahun dimana saya menggunakan Macbook pertama kali setelah menggunakan GNU/Linux penuh waktu. Pada saat itu saya mempelajari Objective-C dan pengembangan menggunakan Storyboard. Saya menyerah mempelajarinya karena hilangnya motivasi dan konsep Storyboard yang membingungkan, sekalipun menggunakan Storyboard bukanlah kewajiban.

Alasan lain? Objective-C. Dukungan Swift masih experimental dan sintaks nya saya rasa lebih rumit dibanding Objective-C pada saat itu. Meskipun demikian, argumen tadi tidak merubah fakta bahwa sintaks Objective-C mengerikan.

Singkat cerita, pada 25 Agustus 2024 kemarin adalah percobaan kedua saya mempelajari iOS development, dengan pengalaman dan pengetahuan yang berbeda dari beberapa waktu yang lalu itu.

Dan di tulisan ini saya ingin berbagi tentang apa yang saya pelajari dengan harapan dapat membantu siapapun yang ingin memulai mengembangkan aplikasi iOS baik secara independen ataupun partai.

Partai kan ya sebutannya klo selain independen?

Hal penting

Untuk mengembangkan aplikasi iOS, memiliki komputer dengan sistem operasi macOS adalah kewajiban. Tidak harus Macbook, sesuatu dengan nama Clover pun bisa! Meskipun akan terdapat kesulitan khususnya karena Apple sekarang cenderung ke arsitektur arm64, tapi bukan berarti mustahil. Setidaknya untuk sekarang.

Selain itu, memiliki Xcode (gratis) pun direkomendasikan. Tentang ini memiliki bagian khusus yang akan kita bahas.

Sebagai catatan terakhir, untuk dapat membuat aplikasi iOS yang dikembangkan dapat dijalankan di perangkat asli (bukan Simulator), diperlukan keanggotaan Apple Developer Program dengan biaya $99/tahun. Di banyak kasus, menggunakan Simulator sendiri pun cukup.

Kecuali jika membutuhkan sesuatu yang berhubungan dengan identitas si pengguna seperti untuk mengirim Push Notification ataupun menampilkan hal lain di layar kunci.

Xcode (IDE)

Saya bukanlah penggemar berat Integrated Development Environment (IDE) namun menggunakan Xcode untuk mengembangkan aplikasi iOS lumayan memuaskan. Fitur favorit saya adalah "Debugging" yang bisa memonitor penggunaan CPU, GPU, memory, baterai dan lain-lain tanpa membuka aplikasi tambahan.

Saat di awal pengembangan, Canvas (preview) akan sangat membantu untuk prototyping, namun saat aplikasi sudah mulai berkembang, saya rasa akan membuat kesulitan tersendiri tergantung bagaimana aplikasi dirancang. Canvas sederhananya adalah versi lebih ringan nya Simulator namun dengan fokus di tampilan antar muka (UI).

Image description

Pratinjau akan terjadi secara instan setiap ada yang berubah, khususnya untuk sesuatu yang berkaitan dengan tampilan. Sederhananya ini seperti fitur "hot reload" yang tidak memerlukan pembuatan ulang segala hal alias hanya bagian yang berubah saja.

Dan sebagaimana aplikasi GUI pada umumnya, hal yang penting dilakukan adalah mengingat shortcut. Preferensi yang saya sesuaikan hanyalah tema, font, dan skema warna, selebihnya, cukup polos.

Sebagai catatan terakhir, Xcode mendukung mode vim. Mungkin kurang berguna untuk beberapa orang, namun untuk beberapa orang—yang memasang vim ataupun ekstensi dimanapun yang mendukung—adalah sebuah killer feature :))

Swift

Untuk yang familiar dengan bahasa pemrograman dari keluarga C (more likely), Swift akan terasa familiar juga; dari sintaks nya, grammar dan conventions (tajwid).

Ini adalah contoh menampilkan "Hello World" di Swift (ke standard output):

print("Hello World")
Enter fullscreen mode Exit fullscreen mode

See, statement tersebut tidak membutuhkan titik koma (maaf pak dhika).

Dan jika datang dari bahasa pemrograman yang berorientasi objek (OOPs), kemungkinan besar akan terasa familiar dengan konsep protocol nya Swift, yang mana Swift adalah bahasa pemrograman berorientasi protokol (POoP).

Sumber belajar Swift (atau bahasa pemrograman lain) favorit saya adalah Learn X in Y Minutes, tapi untuk yang compiled language, biasanya kemarahan compiler dan apapun yang muncul melalui LSP sudah cukup.

Standard library, Core Library dan Framework(s)

Ingat bagaimana perbincangan web frontend developer tentang fetch vs the world, untuk berinteraksi dengan layanan web? Yang biasanya akan berakhir dengan membuat library nya sendiri untuk alasan abstraction dan pada akhirnya bergabung ke golongan axios, ky, dkk dengan versinya sendiri?

Jokes aside, mengetahui standard library yang ditawarkan oleh sebuah bahasa pemrograman adalah tentu saja sebuah kewajiban. Tidak salah menggunakan ky untuk melakukan operasi jaringan secara ✨isomorphic✨ tapi mengetahui bila "under the hood" menggunakan fetch dan node:http (kecuali di node 21) adalah nice thing to know.

Di penggunaan Swift, atau spesifiknya untuk pengembangan aplikasi iOS, pengetahuan tersebut pun berlaku. String (tipe data untuk menampung kumpulan karakter) adalah bagian dari standard library, namun URLSession (yang biasanya digunakan untuk melakukan operasi jaringan) adalah bagian dari Foundation (framework dari Apple, bagian dari Swift Core Library).

Per tulisan ini diterbitkan, setidaknya ada 39 framework yang ditawarkan oleh Apple untuk digunakan (termasuk Foundation). Dan akan lebih mudah dipahami mengapa pengembang iOS lebih memilih Alamofire (3rd party library) alih-alih URLSession secara langsung sebelum mereka membuat yet another Alamofire versi nya daripada pengembang web menggunakan axios/ky/superagent!!! di post fetch arc.

SwiftUI

Ini adalah framework dari Apple untuk membuat aplikasi di iOS sebagaimana anak-anak keren zaman sekarang melakukannya. Killer feature nya adalah menawarkan sintaks yang deklaratif, dan juga, kita setuju pain point yang dimiliki oleh setiap Frontend/UI engineer di berbagai platform adalah di layouting.

Sebelum SwiftUI menjadi keren, framework yang digunakan untuk membuat UI adalah UIKit. Bandingkan ini:

let stackView = UIStackView()
stackView.axis = .horizontal

let label = UILabel()
label.text = "Hello World"

stackView.addArrangedSubview(label)

view.addSubview(stackView)
Enter fullscreen mode Exit fullscreen mode

...yang sangat imperatif, dengan ini yang sangat deklaratif:

<HStack>
  <Text>Hello World</Text>
</HStack>
Enter fullscreen mode Exit fullscreen mode

Just kidding. Seperti ini:

HStack {
  Text("Hello World")
}
Enter fullscreen mode Exit fullscreen mode

Tidak terlihat seperti XML :D

Jika ingin menampilkan teks sesuai kondisi, dan jika yang ada dipikiranmu adalah seperti ini:

  Text(isTodayAGoodDay ? "Hello World" : "Goodbye World")
Enter fullscreen mode Exit fullscreen mode

Maka adalah benar.

Untuk layouting, saya rasa bisa menggunakan mental model "Flexbox" jika sudah familiar dengan teknologi tersebut di platform Web. Yang artinya, jika masih kesulitan untuk membuat konten berada di tengah menggunakan flexbox, besar kemungkinan akan merasakan hal serupa juga di SwiftUI.

Salah satu "gotcha" yang akan dirasakan saat pertama kali menggunakan SwiftUI saya rasa adalah di "method chaining", seperti text ini:

Text("Hello World").background(Color.red)
  .padding(10)
Enter fullscreen mode Exit fullscreen mode

Jika datang dari Go (dan mungkin ECMAScript hipster), tentu sintaks tersebut terasa familiar. Pada dasarnya, singkatnya, kondisi dari sintaks diatas kurang lebih seperti ini:

class Text {
  var background: Color = Color.black
  var padding: CGFloat = 0.0

  func background(_ bgColor: Color) -> Text {
    self.background = bgColor

    return self
  }

  func padding(_ length: CGFloat) -> Text {
    self.padding = length

    return self
  }
}
Enter fullscreen mode Exit fullscreen mode

Bagian yang terpentingnya adalah di bagaimana setiap fungsi mengembalikan si instance objek tersebut. Dan contoh diatas tentu saja adalah versi super simplified nya.

Pola desain

Datang dari frontend development, pola yang paling familiar untuk saya adalah Flux nya Facebook atau serupa seperti Redux. Dari pembuatan aplikasi web secara umum, tentu saja Model View Controller (MVC) kita tercinta.

Secara teknis, di iOS development, Flux bisa diterapkan. Terlebih kita memiliki @EnvironmentObject di SwiftUI. Namun sebagaimana dalam hidup bermasyarakat, kita harus mengikuti dan menghormati tata cara bersosial sebuah perkumpulan, agar mudah diterima dan beradaptasi.

Sejauh yang saya tahu, pola desain favorit dalam pengembangan aplikasi mobile adalah Model View View-Model (MVVM) dan View, Interactor, Presenter, Entity, Router (VIPER).

Dan saya memilih MVVM. Dan sebagaimana setiap pengembang dalam merancang pola, tidak jarang mereka memiliki versi nya sendiri untuk pola desain yang sudah populer.

Konsep utama dalam sebuah pola desain, gampangnya, adalah tentang pemisahan perhatian/separation of concerns: siapa bertanggung jawab apa.

Dalam MVVM, ada 3 hal yang bertanggung jawab dalam melakukan sesuatu:

  • Model: singkatnya yang berkaitan dengan data
  • View: sesuatu yang akan dilihat pengguna
  • View-Model: sesuatu yang menjembatani Model dan View

Dalam kasus otentikasi sebagai contoh, view adalah input username & password; view-model adalah yang mengatur logic untuk view, dan model, biasanya, yang bertanggung jawab seperti untuk melakukan permintaan jaringan.

Secara singkat gambaran kode untuk kasus diatas adalah seperti ini:

// model

struct User: Codable {
  let id: String
  let username: String
}

// view-model

class AuthViewModel: ObservableObject {
  @Published var user: User?

  @Published var username: String = ""
  @Published var password: String = ""
  @Published var alertMessage: String = ""

  @Published var isLoggedIn: Bool = false

  func login() {
    AuthService.shared.login(
      username: username,
      password: password
    ) { result in
      switch result {
        case .success(let data):
          self.isLoggedIn = true

        case .failure(let error):
          self.alertMessage = error.message
      }
    }
  }
}

// view

struct Login: View {
  @ObservedObject var viewModel: AuthViewModel

  var body: some View {
    VStack {
      VStack(alignment: .leading) {
        Text("Username")
        TextField("username", text: $viewModel.username)
      }

      VStack(alignment: .leading) {
        Text("Password")
        SecureField("**********", text: $viewModel.password)
      }

      VStack(alignment: .leading) {
        Button(action: {
          viewModel.login()
        }) {
          Text("Login")
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Dari kode diatas, terlihat bahwa:

  • view tidak memiliki pengetahuan tentang data username, password dan fungsi login
  • viewModel tidak memiliki pengetahuan tentang "apa yang harus dilakukan dengan data tersebut" secara "logika bisnis"
  • model tidak memiliki pengetahuan tentang keduanya, tapi dia tahu apa data yang dibutuhkan agar "bisnis berjalan"

Dari kode diatas, ada satu yang kurang: AuthService. Dalam penerapan MVVM versi saya, saya meminjam konsep "interactor" dari VIPER: ada bagian khusus yang bertanggung jawab dalam melakukan "network calls", dan juga saya prefer menganggap "model" sebagai "entity", the og pdo.

Namun intinya adalah gunakan pola yang khususnya tidak membingungkanmu dan apalagi tidak membingungkan orang lain.

Lagipula, setiap program memiliki konsep yang sama: satu entrypoint yang akan mengatur keseluruhan siklus hidup sebuah program. Yang maksudnya, tidak ada yang memberhentikanmu untuk menulis seluruh kode di satu file yang bertindak sebagai entrypoint.

Dalam menggunakan pola, seperti hidup, akan membuatnya menjadi rapih. Jika rapih, maka mudah diatur. Butuh waktu lebih lama untuk saya memahami pola MVVM secara umum, namun hasilnya, membuat saya lebih mengerti apa yang saya buat dan lakukan.

Continuous Integration/{Delivery,Deployment} (CI/CD)

Sebagai pengembang yang malas, bob selalu ingin mengotomatisasikan sebanyak dan sebisa mungkin. Saya adalah bob, bob adalah kita semua.

Sebagaimana namanya, CI sangat berperan khususnya dalam kerja sama tim. CI berguna untuk memastikan "kolaborasi" yang dilakukan dalam menulis kode tidak merusak kode lain, khususnya yang ditulis oleh orang lain. Selain itu, CI pun berguna untuk memastikan kode yang sudah ada tidak rusak yang salah satunya karena dilekang oleh waktu.

Dalam konteks iOS development, ada beberapa hal yang menyebalkan:

  • Provisioning profile. Ini berguna untuk build & run program. Umumnya, setiap developer akan menggunakan profile nya sendiri. Idealnya, setiap developer akan menggunakan profile yang sama
  • Delivery ke beta channel (TestFlight). Salah satu cara yang paling sederhana adalah dengan melakukan Archive melalui Xcode. Ada setidaknya 3 step yang harus dilalui dan sesederhana klik-klik tombol. Jika setiap minggu merilis aplikasi ke channel beta dan setiap proses memakan waktu 2 menit, dalam setahun menghabiskan 1.6 jam hanya untuk itu, dengan catatan durasi nya konsisten 2 menit.

Tools yang cukup populer di komunitas iOS adalah Fastlane, dan fitur (actions) yang paling populer digunakan menurut saya adalah pilot untuk melakukan beta deployment dan match untuk mengatur provisioning profile yang berperan untuk code signing.

Xcode memiliki fitur "managed code signing" yang pada dasarnya doi akan memilih "sertifikat paling terakhir yang paling valid". Ketidakpastian ini menimbulkan pertanyaan "sertifikat apa yang paling terakhir dan yang paling valid?" namun yang paling penting "milik siapa?" karena jika mengubah provisining profile, dan menggunakan Source Code Management (SCM) seperti git, perubahan tersebut besar kemungkinan akan dilacak.

Namun selebihnya terkait CI/CD, tidak berbeda jauh dengan sistem CI/CD yang sudah ada: seseorang membuat sesuatu untuk mengatur sebuah sistem agar melakukan sesuatu, yg umumnya secara deklaratif. Alur kerja yang cukup umum adalah "build project setiap kali ada commit baru yang masuk ke cabang develop", misalnya.

Tentang TestFlight

TestFlight intinya adalah tentang mengirimkan aplikasi ke beberapa grup sebelum dikirimkan ke khalayak. Grup ini memiliki dua sifat: ada yang private (internal) dan public (khalayak). Untuk grup public, review tetap harus dilakukan oleh pihak Apple agar aplikasi tersebut dapat diuji oleh si "peserta".

Sebagaimana yang sudah disebutkan, yakni membutuhkan keanggotaan Apple Developer Program untuk dapat menjalankan aplikasi di perangkat asli. Sehingga, keanggotaan tersebut adalah kewajiban untuk dapat menggunakan TestFlight, sekalipun untuk grup private ataupun di perangkat sendiri.

Image description

Tidak ada yang spesial dari TestFlight selain untuk mengirimkan aplikasi untuk dicoba oleh peserta/pengguna sebelum aplikasi tersebut dapat digunakan oleh khalayak. Namun, setiap aplikasi yang akan dikirimkan ke App Store akan melewati TestFlight terlebih dahulu.

Tentang App Store

App Store adalah satu-satunya tempat untuk menyimpan aplikasi agar dapat dicari, dipasang dan digunakan oleh pengguna iOS, atau setidaknya untuk pengguna iOS non warga EU.

Tidak sedikit adanya cerita horor dan drama terkait proses agar membuat aplikasi berhasil berada di App Store, yang untuk pendatang baru seperti saya, menimbulkan kekhawatiran yang seharusnya tidak perlu. Salah satu sumber yang membuat kekhawatiran tersebut adalah App Review Guidelines yang membutuhkan perhatian lebih.

Namun aturan praktis nya, berdasarkan yang saya pahami, ada 3:

  1. Pastikan aplikasi tersebut "berguna" untuk digunakan oleh pengguna
  2. Pastikan informasi yang diberikan relevan dengan kondisi nyata
  3. Pastikan, jika berhubungan dengan pihak ketiga, mengikuti kebijakan yang ada

Kata berguna diatas sengaja memiliki tanda kutip karena pada akhirnya termasuk ambigu. Bayangkan harus memasukkan "aplikasi internal" ke App Store karena hanya itu satu-satunya cara, yang mana aplikasi tersebut berguna untuk audiens "internal" tersebut (whatever that is) namun mungkin tidak berguna untuk khalayak.

Di percobaan pertama saya, permintaan saya ditolak karena tidak mematuhi pedoman 2.1 terkait "App Completeness"

Image description

Bunyi dari pedoman 2.1 per tanggal 19 September 2024 adalah seperti ini:

(a) Submissions to App Review, including apps you make available for pre-order, should be final versions with all necessary metadata and fully functional URLs included; placeholder text, empty websites, and other temporary content should be scrubbed before submission. Make sure your app has been tested on-device for bugs and stability before you submit it, and include demo account info (and turn on your back-end service!) if your app includes a login. If you are unable to provide a demo account due to legal or security obligations, you may include a built-in demo mode in lieu of a demo account with prior approval by Apple. Ensure the demo mode exhibits your app’s full features and functionality. We will reject incomplete app bundles and binaries that crash or exhibit obvious technical problems.

(b) If you offer in-app purchases in your app, make sure they are complete, up-to-date, visible to the reviewer and functional. If any configured in-app purchase items cannot be found or reviewed in your app, explain the reason in your review notes.

Silahkan korelasikan si pedoman 2.1 ini dengan pesan penolakannya. Namun yang terpenting adalah bagian dari next steps nya:

Provide a link to the video in the App Review Information section of your the app's page in App Store Connect and reply to this message. A screen recorder can be used to capture footage of the app in use. Note that if the app can only be reviewed with a demo video, updated demo videos will need to be provided for every app submission.

Saya tidak menyertakan video karena di bagian "Attachments" pesannya adalah seperti ini:

You can attach specific app documentation, demo videos, and other items to help prevent delays during the app review process. Make sure you use files with the following extensions: .pdf, .doc, .docx, .rtf, .pages, .xls, .xlsx, .numbers, .zip, .rar, .plist, .crash, .jpg, .png, .mp4, or .avi.

Kata yang saya perhatikan hanyalah di bagian "you can" dan "to help prevent delays". Bagaimanapun, saat mengikuti bagian dari Next Steps tersebut, berikut hasilnya:

Image description

Hell yeah.

Intinya, saya rasa App Store review tidak seseram itu selama kita "tunduk" kepada pedoman/aturan yang sudah ada (sampai Apple berkata lain).

Penutup

Saya rasa barrier terbesar untuk terjun ke iOS development adalah kepemilikan perangkat. Karena sisanya, saya rasa sama seperti mengembangkan aplikasi pada umumnya: menulis sebuah instruksi untuk membuat komputer melakukan sesuatu.

Tapi menariknya, saya tidak memiliki referensi untuk mempelajari iOS development. Saya mempercayai Xcode 100% sampai si Xcode tersebut tidak bisa mendeteksi error yang besar kemungkinan karena terjadi di runtime. Hal yang menyebalkan mungkin di bagian "deprecated" APIs yang mana saya ambil dari tulisan random di internet. Namun, selama build berhasil, maka build berhasil (sampai suatu saat tidak berhasil).

Sebagai penutup, shameless plug. Saya mengembangkan aplikasi iOS bernama flo - Navidrome Client, yang, sebagaimana judulnya, adalah klien (iOS) untuk Navidrome. Aplikasi tersebut gratis, Open Source, dan ditulis menggunakan "Swift murni" (double quotes for jokes).

Oh, dan menggunakan SwiftUI serta pola FMVVM (faultables' Model View View-Model) yang mungkin bisa membantu untuk mempelajari iOS development.

Terakhir, mengembangkan aplikasi adalah bagian yang paling mudah dari membuat aplikasi yang khususnya bertujuan untuk digunakan oleh khalayak. Bagian yang paling menantangnya adalah membuat khalayak untuk menggunakan aplikasi yang dikembangkan tersebut.

Dan tulisan ini, pada dasarnya adalah salah satu usahanya. Pemasaran bukanlah hal yang saya sukai, namun, saya sudah lama tertarik dengan posisi Developer Relations/DevRel yang pada dasarnya adalah memasarkan sesuatu untuk audiens fellow developers.

Namun jika dirasa tidak membutuhkan klien (iOS) untuk Navidrome, setidaknya kamu sudah mengetahui informasinya, dan mungkin teman ataupun temannya temanmu membutuhkannya :D

Karena pada akhirnya, bagaimana orang lain bisa tahu apa yang kamu lakukan jika kamu tidak memberitahukannya?

Dan untungnya, bumi masih berputar.

Top comments (0)