Yaron Jackoby

iOS & Android Developer

Crafting exceptional mobile experiences with Swift and Kotlin

iOS and Android Devices
// Swift Code Sample
func createAwesomeApp() {
    let experience = 20
    let passion = 100
    
    let result = buildApp(with: experience, 
                         and: passion)
    
    deployToAppStore(result)
}

About Me

Yaron Jackoby

Mobile Developer with 20+ Years Experience

Hello! I'm Yaron, a passionate mobile app developer specializing in creating robust and user-friendly applications for iOS and Android platforms. With over a decade of experience in the industry, I've developed a wide range of applications from concept to launch.

My expertise spans Swift and Objective-C for iOS development and Kotlin and Java for Android. I'm committed to writing clean, maintainable code and creating intuitive user experiences that delight users.

20+

Years Experience

100%

Client Satisfaction

My Skills

iOS Development

Swift

UIKit

SwiftUI

Objective-C

Android Development

Kotlin

Java

Android SDK

Backend Development

Go Lang

Python

TypeScript

PHP

Cross-Platform

Flutter

Apple Ecosystem Expertise

I develop iOS apps with full Apple ecosystem integration, providing seamless experiences across all Apple devices.

iPhone

Creating polished, high-performance native iOS applications with beautiful UIs and fluid animations.

iPad

Developing iPad-optimized apps with adaptive layouts and multitasking support for productivity.

MacOS

Building Mac apps using Catalyst or native AppKit, optimized for desktop interactions.

Apple Watch

Creating watchOS apps and complications with efficient interfaces for wearable experiences.

Apple TV

Developing tvOS apps with focus-based navigation and engaging large-screen experiences.

Audio Integration

Implementing AirPlay, AirPods, and HomePod connectivity for immersive audio experiences.

Work Experience

Senior Mobile Developer

Tech Innovations Inc.

2019 - Present

Lead developer for iOS and Android applications, managing a team of 5 developers. Implemented CI/CD pipelines and reduced app crash rates by 95%.

Swift Kotlin SwiftUI Jetpack Compose

Mobile Developer

App Solutions Ltd.

2016 - 2019

Developed and maintained multiple iOS and Android applications serving over 500,000 users. Implemented complex features and optimized app performance.

Swift Java Objective-C Firebase

iOS Developer

Mobile First Agency

2013 - 2016

Specialized in iOS development for various clients across different industries. Built and deployed 15+ apps to the App Store.

Objective-C Swift Core Data REST APIs

Companies I've Worked With

Throughout my career, I've had the privilege of working with these outstanding companies, delivering mobile solutions across various industries.

Conduit

Fring

Genband

Oovoo

EVM

Reporty

Engie

Tunity

Swift vs Kotlin Code Comparison

As a master of both iOS and Android development, I'm fluent in both Swift and Kotlin. Here's how similar functionality looks in both languages:

Swift (iOS)



// Network request in Swift
import Foundation

class SchoolSearchViewModel: ObservableObject {
    @Published var schools: [SchoolLocation] = []
    @Published var isLoading = false
    @Published var errorMessage: String?

    func fetchSchools() {
        isLoading = true
        errorMessage = nil

        let url = "https://nominatim.openstreetmap.org/search"
        let parameters: Parameters = [
            "limit": "10",
            "bounded": "1",
            "viewbox": "-0.1366,51.5260,-0.1246,51.5170",
            "amenity": "school",
            "addressdetails": "1",
            "format": "json"
        ]

        AF.request(url, parameters: parameters)
            .validate()
            .responseDecodable(of: [SchoolLocation].self) { response in
                DispatchQueue.main.async {
                    self.isLoading = false
                    switch response.result {
                    case .success(let data):
                        self.schools = data
                    case .failure(let error):
                        self.errorMessage = error.localizedDescription
                    }
                }
            }
    }
}

Kotlin (Android)


class SchoolSearchViewModel : ViewModel() {
    private val _schools = MutableLiveData>()
    val schools: LiveData> = _schools

    private val _isLoading = MutableLiveData(false)
    val isLoading: LiveData = _isLoading

    private val _errorMessage = MutableLiveData()
    val errorMessage: LiveData = _errorMessage

    fun fetchSchools() {
        _isLoading.value = true
        _errorMessage.value = null

        val params = mapOf(
            "limit" to "10",
            "bounded" to "1",
            "viewbox" to "-0.1366,51.5260,-0.1246,51.5170",
            "amenity" to "school",
            "addressdetails" to "1",
            "format" to "json"
        )

        viewModelScope.launch {
            try {
                val result = RetrofitClient.api.searchSchools(params)
                _schools.value = result
            } catch (e: Exception) {
                _errorMessage.value = e.localizedMessage
            } finally {
                _isLoading.value = false
            }
        }
    }
}

Swift (SwiftUI)

import SwiftUI

struct LoginView: View {
    @State private var username: String = ""
    @State private var isLoggedIn: Bool = false
    
    var body: some View {
        VStack(spacing: 20) {
            Text("Welcome")
                .font(.largeTitle)
                .fontWeight(.bold)
            
            TextField("Username", text: $username)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
            
            Button(action: {
                // Handle login
                isLoggedIn = !username.isEmpty
            }) {
                Text("Login")
                    .foregroundColor(.white)
                    .padding()
                    .background(Color.blue)
                    .cornerRadius(8)
            }
            
            if isLoggedIn {
                Text("Hello, \(username)!")
                    .font(.title)
                    .padding()
            }
        }
        .padding()
    }
}
#Preview {
    SampleView()
        .preferredColorScheme(.light)
}

Kotlin (Jetpack Compose)

package com.yaronj.myviewsample

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun LoginScreen() {
    var username by remember { mutableStateOf("") }
    var isLoggedIn by remember { mutableStateOf(false) }

    Column(modifier = Modifier.padding(16.dp)) {
        Text(text = "Welcome", style = MaterialTheme.typography.headlineLarge)

        Spacer(modifier = Modifier.height(16.dp))

        OutlinedTextField(
            value = username,
            onValueChange = { username = it },
            label = { Text("Username") },
            modifier = Modifier.fillMaxWidth()
        )

        Spacer(modifier = Modifier.height(16.dp))

        Button(
            onClick = {
                if (username.isNotBlank()) {
                    isLoggedIn = true
                } else {
                    isLoggedIn = false
                }
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Login")
        }
        Row(modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.Center) {
            if (isLoggedIn && username.isNotBlank()) {
                Text(text = "Welcome, $username!",
                        style = MaterialTheme.typography.headlineLarge)
                }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun LoginScreenPreview() {
    LoginScreen()}

Swift (Contacts)

// Contacts programming in Swift
import Foundation

struct User: Codable {
    let id: Int
    let name: String
}


import Foundation
import Contacts
import SwiftUI

enum ContactError: Error {
    case accessDenied
    case unknown
}

struct ContatctItem: Identifiable {
    var id = UUID().uuidString
    let name: String
    let email: String?
    let phone: String?
    
    init(contact: CNContact) {
        self.name = "\(contact.givenName) \(contact.familyName)"
        self.email = contact.emailAddresses.first?.value as String?
        self.phone = contact.phoneNumbers.first?.value.stringValue
    }
}

@MainActor class ContactsViewModel: ObservableObject {
    @Published var contacts: [ContatctItem] = []
    private let contactStore = CNContactStore()
    private var keysToFetch: [CNKeyDescriptor] {
        let keys = [
            CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
            CNContactEmailAddressesKey as CNKeyDescriptor,
            CNContactPhoneNumbersKey as CNKeyDescriptor,
            CNContactImageDataKey as CNKeyDescriptor,
            CNContactThumbnailImageDataKey as CNKeyDescriptor,
            CNContactIdentifierKey as CNKeyDescriptor,
            CNContactGivenNameKey as CNKeyDescriptor,
            CNContactFamilyNameKey as CNKeyDescriptor,
            CNContactOrganizationNameKey as CNKeyDescriptor
        ]
        return keys
    }
    
    init() {
        Task {
            do {
                let localContacts = try await fetchContacts()
                self.contacts = localContacts
            } catch {
                print("Error fetching contacts: \(error)")
            }
        }
    }
    
    func fetchContacts() async throws -> [ContatctItem] {
        do {
            // Request permission first
            let authStatus = CNContactStore.authorizationStatus(for: .contacts)
            switch authStatus {
            case .notDetermined:
                let granted = try await contactStore.requestAccess(for: .contacts)
                guard granted else {
                    throw ContactError.accessDenied
                }
            case .restricted, .denied:
                throw ContactError.accessDenied
            case .authorized:
                break
            case .limited:
                print("Limited access granted")
            @unknown default:
                throw ContactError.unknown
            }
        }
        return try await Task.detached(priority: .userInitiated) { [keys = self.keysToFetch] in
            let contactStore = CNContactStore()
            var allContacts: [CNContact] = []
            let fetchRequest = CNContactFetchRequest(keysToFetch: keys)
            
            try contactStore.enumerateContacts(with: fetchRequest) { contact, stop in
                if let completeContact = try? contactStore.unifiedContact(
                    withIdentifier: contact.identifier,
                    keysToFetch: keys
                ) {
                    allContacts.append(completeContact)
                }
            }
            
            return allContacts.map { ContatctItem(contact: $0) }
        }.value
    }
}

Kotlin (Contacts)

// Contacts programming in Kotlin
package com.yaronj.contacts

import android.content.Context
import android.provider.ContactsContract
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.*

data class ContactItem(
    val id: String = UUID.randomUUID().toString(),
    val name: String,
    val email: String?,
    val phone: String?
)

class ContactsViewModel(private val context: Context) : ViewModel() {

    private val _contacts = MutableStateFlow>(emptyList())
    val contacts: StateFlow> = _contacts

    init {
        loadContacts()
    }

    private fun loadContacts() {
        viewModelScope.launch {
            _contacts.value = fetchContacts(context)
        }
    }

    private suspend fun fetchContacts(context: Context): List {
        return withContext(Dispatchers.IO) {
            val contactList = mutableListOf()
            val contentResolver = context.contentResolver

            val cursor = contentResolver.query(
                ContactsContract.Contacts.CONTENT_URI,
                null, null, null, null
            ) ?: return@withContext emptyList()

            while (cursor.moveToNext()) {
                val contactId = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID))
                val name = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)) ?: ""

                // Fetch phone number
                var phone: String? = null
                if (cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
                    val phoneCursor = contentResolver.query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null,
                        "${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} = ?",
                        arrayOf(contactId),
                        null
                    )
                    phoneCursor?.use {
                        if (it.moveToFirst()) {
                            phone = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER))
                        }
                    }
                }

                // Fetch email
                var email: String? = null
                val emailCursor = contentResolver.query(
                    ContactsContract.CommonDataKinds.Email.CONTENT_URI,
                    null,
                    "${ContactsContract.CommonDataKinds.Email.CONTACT_ID} = ?",
                    arrayOf(contactId),
                    null
                )
                emailCursor?.use {
                    if (it.moveToFirst()) {
                        email = it.getString(it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.ADDRESS))
                    }
                }

                contactList.add(ContactItem(name = name, email = email, phone = phone))
            }

            cursor.close()
            return@withContext contactList
        }
    }
}
}

Get In Touch

Let's Work Together

Have a project in mind? Get in touch and let's create something amazing together.

yaron.jackoby@gmail.com
+(972)52-257-57-80
Tel Aviv, Israel