How to Transfer Files Between Android and iOS using TCP?

How to Transfer Files Between Android and iOS using TCP?

Transferring files between Android and iPhone often feels simple in theory but difficult in practice.

Both platforms have their own file-sharing methods, device communication rules, and security controls, which can make direct file transfer challenging.

For users, this usually means depending on cloud storage, email, messaging apps, or third-party tools.

For developers, the challenge is bigger because cross-platform mobile apps need a reliable way to exchange files, media, documents, or app data without breaking the user experience.
TCP offers a practical solution for this. By using TCP sockets, Android and iOS applications can establish a direct communication channel and transfer files reliably between devices.

In this article, we will look at how file transfer between Android and iOS can be implemented using TCP.

Best way to transfer files between Android and iOS

Hi Developers,

I am going to share the best way to transfer files between Android and iOS.

I shared the full code for working on cross-platform file sharing (between Android and iOS) issues and solutions.

When I worked on an Android app project, I was restricted from using Lollipop OS due to Java 8 did not support it.

So, you may or may not face the same issue depending on what you are trying to achieve.

First of all, Let’s define what jReto and SReto are.

  1. jReto: P2P Framework for real-time collaboration in Java.
  2. SReto: P2P Framework for real-time collaboration in Swift.
Reto is an extensible P2P network platform used in Java 8 and Swift. It delivers the APIs in both languages.

The features of this frame are:

  • Peer discovery
  • Putting connections between peers
  • Acting cancellable data transfers
  • Features assistance for routed connections (i.e., peers that Can’t directly communicate could Nevertheless Be found and utilize other peers to forward information)

This module allows peers to discover one another and discuss over the Web whether a RemoteP2P server is necessary.

  1. WLAN module: Enables peer discovery and connectivity in LAN (Local Area Networks) by using Bonjour for detection (locating) and regular TCP/IP connections for information transfers.
  2. RemoteP2PModule: Uses an internet server to facilitate communication between peers. This module enables peers to discover one another and discuss over the Web; Still, a RemoteP2P server is required.

Now! Let’s shorten it down in our example.

jReto (Android) /SReto ( iOS ) + Bonjour service: Finding devices and sending objects.

We used Bonjour Discovery to find out nearby running the same services to send and receive files for cross-platform file sharing.

We can act as servers and clients by broadcasting and seeking service usage.

Here I prepared a code for it. So, you can use it directly in your project or application. i.e. android is a broadcasting ( advertising ) service, which can be discovered by the client.

Why Sending Files Between Android and iPhone Can Be Challenging

Transferring files between devices becomes effortless when both devices belong to the same ecosystem.

However, sharing files between Android and iPhone often introduces additional steps because each platform is designed with its own technologies, security standards, and communication mechanisms.

Several factors contribute to these challenges:

Different Platform Architectures

Android and iOS are developed independently and use different frameworks, system services, and file management structures.

As a result, features that work natively within one ecosystem may not function directly with the other.

Limited Native Cross-Platform Sharing

Both platforms provide built-in file-sharing capabilities for their own devices.

While these solutions offer a convenient experience within the same ecosystem, they typically do not provide direct interoperability between Android and iOS devices.

Security and Privacy Controls

Modern mobile operating systems enforce strict security measures to protect user data.

Permission requirements, network restrictions, and privacy policies can limit how applications discover devices and exchange files across platforms.

Dependence on External Services

Many users rely on cloud storage platforms, email attachments, messaging applications, or third-party transfer tools when moving files between Android and iPhone.

Although effective, these methods may introduce additional upload times, internet dependency, or file size limitations.

Maintaining Reliable Data Transfer

When transferring large files, maintaining connection stability and ensuring complete data delivery becomes essential.

Any interruption during transmission can result in incomplete transfers or corrupted files if proper communication protocols are not used.
Because of these challenges, developers often implement networking protocols such as TCP to establish direct and reliable communication between Android and iOS applications.

TCP provides connection-oriented communication, verifies data delivery, and helps ensure that files are transferred accurately between devices, making it a suitable choice for cross-platform file-sharing applications.

Android Java Broadcaster


// 1. Create the WlanModule
WlanModule wlanModule = new WlanModule("ExampleType");

// 2. Create the LocalPeer
LocalPeer localPeer = new LocalPeer(Arrays.asList(SatvaTutorial), Executors.newSingleThreadExecutor());

// 3. Starting the LocalPeer
localPeer.start(
    discoveredPeer -> System.out.println("Discovered peer: " + discoveredPeer),
    removedPeer -> System.out.println("Removed peer: " + removedPeer),
    (peer, incomingConnection) -> System.out.println("Received incoming connection: " + incomingConnection + " from peer: " + peer)
);

iOS Swift Broadcaster


func startBroadcast() {
    socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
    do {
        try socket.accept(onPort: 0)
        service = NSNetService(domain: "", type: "_test._tcp", name: "SatvaTutorial", port: Int32(socket.localPort))
    } catch {
        print("Error listening on port")
    }
    
    if let service = service {
        service.delegate = self
        service.publish()
    }
}

func netServiceDidPublish(sender: NSNetService) {
    guard let service = service else {
        return
    }
    print("Successfully published on port \(service.port) / domain: \(service.domain) / type: \(service.type) / name: \(service.name)")
}

  • Ensure that your class conforms to the required protocols for GCDAsyncSocketDelegate and NSNetServiceDelegate.
  • Make sure to import necessary frameworks at the top of your Swift file:

import CocoaAsyncSocket
import Foundation

  • Only the same name service can be discovered by the client to connect with.
  • Once we find a broadcasting service from the server we can go ahead and can connect to the server.

func netServiceBrowser (browser: NSNetServiceBrowser , didFindService service: NSNetService , moreComing: Bool ) {
services . addObject (service)
connect ()
}
func connect () {
service = services . firstObject ! ash ! NSNetService
service . delegate = self
service . resolveWithTimeout ( 30.0 )
}
  • i.e. Android broadcasted its service and iPhone ( which is seeking for service to get connected with ) found service on the same network to connect with.

func netServiceDidResolveAddress(sender: NSNetService) {
    if connectWithService(sender) {
        print("Did connect with service")
    } else {
        print("Error connecting with service")
    }
}
  • Once the connection was established, we tried to share files from one platform to another ( here iOS to Android ).

Receiving Data on Android


someConnection.setOnTransfer((connection, transfer) -> {
    // 2. Configuring a transfer to let you handle data as it is received, instead of letting the transfer buffer all data
    transfer.setOnPartialData((transfer, data) -> {
        System.out.println("Received a chunk of data!");
    });

    // 3. Registering for progress updates
    transfer.setOnProgress(transfer -> {
        System.out.println("Current progress: " + transfer.progress + " of " + transfer.length);
    });
});

// 4. Sending a transfer example
let transfer = someConnection.send(someData.length, range -> {
    return somehowProvideDataForRange(range);
});

// 5. Registering for progress updates
transfer.setOnProgress(transfer -> {
    System.out.println("Current progress: " + transfer.progress + " of " + transfer.length);
});

Sending Data from iOS


func connectWithService(service: NSNetService) -> Bool {
    var isConnected = false
    guard let addresses = service.addresses else { return false }

    if socket == nil || !socket.isConnected {
        socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)

        // Connect
        var count = 0
        while !isConnected && count < addresses.count {
            let address = addresses[count] as! NSData
            count += 1
            do {
                try socket.connect(toAddress: address as Data)
                isConnected = true
            } catch {
                print("Failed to connect")
            }
        }
    } else {
        isConnected = socket.isConnected
    }
    
    return isConnected
}

func sendPacket(packet: Packet) {
    let packetData = NSKeyedArchiver.archivedData(withRootObject: packet)
    let packetDataLength = packetData.count
    var buffer = NSMutableData(bytes: &packetDataLength, length: MemoryLayout.size)
    buffer.append(packetData)
    socket.write(buffer as Data, withTimeout: -1, tag: 0)
}
We observed that files that are being transferred on a TCP connection are chunked into small bytes which created an issue on the Android side to read ( due to a heap memory issue ).

someConnection.setOnTransfer(
(connection, transfer) ->
// 2. Configuring a transfer to let you handle data as it is received, instead of letting the transfer buffer all data
transfer.setOnPartialData((transfer, data) -> System.out.println(“Received a chunk of data!”));
// 3. Registering for progress updates
transfer.setOnProgress(transfer -> System.out.println(“Current progress: “+transfer.progress+” of “+transfer.length));
);
// 4. Sending a transfer example
let transfer = someConnection.send(someData.length, range -> somehowProvideDataForRange(range));
// 5. Registering for progress updates
transfer.setOnProgress(transfer -> System.out.println(“Current progress: “+transfer.progress+” of “+transfer.length));

func socket(sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
    print("Socket accepted")
    socket = newSocket
    socket.delegate = self
    socket.readData(toLength: UInt(MemoryLayout.size), withTimeout: -1, tag: 1)
}

func socket(sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
    if tag == 1 {
        var bodyLength: Int16 = 0
        data.copyBytes(to: &bodyLength, count: MemoryLayout.size)
        print("Header received with body length: \(bodyLength)")
        socket.readData(toLength: UInt(bodyLength), withTimeout: -1, tag: 2)
    } else if tag == 2 {
        if let packet = NSKeyedUnarchiver.unarchiveObject(with: data) as? Packet {
            PacketHandler.handlePacket(packet)
        }
        socket.readData(toLength: UInt(MemoryLayout.size), withTimeout: -1, tag: 1)
    }
}
Which did not help share a large file between two devices.

Final Workaround

After facing the above issue, we tried many ways including the web socket as well, but due to its file transfer speed issue wasn’t that handy technique to implement.
  • We decided to simply create an observer and listener with the same connection name.
  • After that, we tried to connect and shared a file using a fast socket from iOS to Android.

func connectWithService(service: NSNetService) -> Bool {
    var isConnected = false
    guard let addresses = service.addresses else {
        return isConnected
    }
    
    if socket == nil || !socket.isConnected {
        socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
        
        // Connect
        for address in addresses {
            do {
                try socket.connect(toAddress: address as Data)
                isConnected = true
                break // Exit the loop if successfully connected
            } catch {
                print("Failed to connect: \(error.localizedDescription)")
            }
        }
    } else {
        isConnected = socket.isConnected
    }
    return isConnected
}

func sendPacket(packet: Packet) {
    let packetData = NSKeyedArchiver.archivedData(withRootObject: packet)
    let packetDataLength = packetData.count
    var buffer = Data(capacity: MemoryLayout.size + packetDataLength)
    var length = Int16(packetDataLength)
    
    // Append the length of the packet data
    buffer.append(Data(bytes: &length, count: MemoryLayout.size))
    // Append the actual packet data
    buffer.append(packetData)
    
    socket.write(buffer, withTimeout: -1, tag: 0)
}

@IBAction func btnSendImage(_ sender: Any) {
    do {
        let client = FastSocket(host: "192.168.43.1", andPort: "8080")
        
        // Attempt to connect to the server
        if client.connect() {
            print("Server connected")
            
            // Load the image and convert it to PNG data
            if let imageData = UIImage(named: "samplefile.png")?.pngData() {
                // Send image data as bytes
                imageData.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
                    if let baseAddress = bytes.baseAddress {
                        let sentBytes = client.sendBytes(baseAddress.assumingMemoryBound(to: UInt8.self), count: imageData.count)
                        print("Bytes sent: \(sentBytes)")
                    }
                }
            } else {
                print("Failed to load image data.")
            }
        } else {
            print("Failed to connect to the server.")
        }
    } catch {
        print("Error occurred: \(error.localizedDescription)")
    }
}
Which turned out to be helpful.
The only issue we found was that we could not pass the header file along with the file to identify the file type.

Guys, I hope you like my article. I intend to save you time and help other developers to solve the same issues during mobile application development.

Let’s have a meeting with our mobile app developers and work together on your problems.

Conclusion

Transferring files between Android and iOS devices often presents challenges due to differences in platform architecture, native sharing capabilities, and security restrictions.

While cloud services and third-party applications can help bridge this gap, they may introduce additional dependencies, upload delays, or limitations when handling larger files.

A TCP-based approach offers a reliable alternative by establishing direct communication between devices and ensuring that data is delivered accurately and in the correct sequence.

By implementing file transfer using TCP sockets, developers can build cross-platform mobile applications that support secure and efficient data exchange between Android and iOS devices.

Whether the goal is to share documents, media files, or application data, TCP provides a dependable foundation for maintaining file integrity and improving the overall user experience.

With the right implementation strategy, developers can create scalable file-sharing solutions that work consistently across different mobile ecosystems.

Frequently Asked Questions (FAQs)

What is TCP file transfer between Android and iOS?

TCP file transfer is a method of sending files between Android and iOS devices using the Transmission Control Protocol (TCP). It establishes a direct connection between devices and ensures reliable delivery of data throughout the transfer process.

Why use TCP instead of cloud storage for file sharing?

TCP enables direct device-to-device communication without requiring files to be uploaded to an external cloud service. This can reduce transfer delays, improve privacy, and provide greater control over data transmission.

Is TCP reliable for transferring large files?

Yes. TCP is designed to provide reliable communication by verifying data delivery, managing packet sequencing, and retransmitting lost packets when necessary. This makes it suitable for transferring large files between mobile devices.

Can Android and iOS communicate directly using TCP sockets?

Yes. Both Android and iOS support socket programming, allowing applications on different platforms to establish TCP connections and exchange data directly over a network.

What types of files can be transferred using TCP?

TCP can be used to transfer various file types, including images, videos, PDFs, documents, spreadsheets, audio files, application-generated content, and other binary data.

Does TCP require an internet connection for file transfer?

Not necessarily. TCP communication can operate over local Wi-Fi networks, private networks, or internet-connected environments, depending on the application architecture and deployment requirements.

How does TCP ensure file integrity during transfer?

TCP uses acknowledgements, packet sequencing, error checking, and retransmission mechanisms to ensure that all data reaches the destination correctly and in the proper order.

Is TCP secure for transferring files?

TCP itself focuses on reliable communication. For secure file transfer, developers typically combine TCP with encryption technologies such as SSL/TLS to protect data while it is transmitted between devices.

What are the benefits of using TCP for cross-platform mobile applications?

Benefits include reliable data delivery, support for large file transfers, real-time communication capabilities, platform independence, error recovery mechanisms, and compatibility across Android and iOS devices.

When should developers choose TCP over UDP for file transfer?

TCP is generally preferred when data accuracy and complete file delivery are critical. Unlike UDP, TCP verifies packet delivery and ensures that files arrive intact without missing or out-of-order data.

Can TCP be used for real-time mobile application communication?

Yes. TCP is commonly used for messaging systems, collaborative applications, enterprise solutions, file-sharing platforms, and other mobile applications that require reliable real-time communication.

What industries commonly use TCP-based file transfer solutions?

TCP-based file transfer is widely used in healthcare, finance, logistics, education, enterprise collaboration, manufacturing, document management systems, and other industries that require dependable data exchange between applications and devices.

Article by

Chintan Prajapati

Chintan Prajapati is the Founder and CEO of Satva Solutions and a seasoned computer engineer with over two decades of experience in the software industry. His expertise spans Accounting & ERP Integrations, Robotic Process Automation, and the development of technology solutions built around leading ERP and accounting platforms with a particular focus on responsible AI and machine learning in fintech.Chintan holds a BE in Computer Engineering and carries an impressive roster of certifications, including Microsoft Certified Professional, Microsoft Certified Technology Specialist, Certified Azure Solution Developer, Certified Intuit Developer, Certified QuickBooks ProAdvisor, and Xero Developer.Over the course of his career, he has made a measurable impact on the accounting industry consulting on and delivering integration and automation solutions that have collectively saved thousands of man-hours. His writing aims to offer readers practical, insight-driven advice on harnessing technology to unlock greater business efficiency.When he steps away from the desk, Chintan can be found trekking through mountain trails or watching birds in the wild. Grounded in the philosophy of delivering the highest value to clients, he continues to champion innovation and excellence in digital transformation from his home base in Ahmedabad, India.