2018년 4월 8일 일요일

usb connection to pc in Android(1)


파일 공유

안드로이드 장치와 PC간 간단한 전송이 필요한 경우가 발생하였다. 어떻게 할까 고민하다가 가장 간단한 파일에 기록을 하고 한쪽에서는 파일을 가져가고 하면 될 것 같다.

PC : adb push / adb pull 명령을 이용한다.
Android app : File write / read 를 이용한다.



Socket 이용

ADB에 포트 전달 설정을 이용할 수 있다.
호스트 포트를 기기의 다른 포트로 전달합니다. 이번에 설명하고자 하는 내용입니다.
https://developer.android.com/studio/command-line/adb.html

포트 전달 설정


forward 명령을 사용하여 임의의 포트 전달을 설정할 수 있습니다. 즉, 특정 호스트 포트의 요청을 에뮬레이터/기기 인스턴스의 다른 포트로 전달합니다. 다음은 호스트 포트 6100에서 에뮬레이터/기기 포트 7100으로의 전달을 설정하는 방법입니다.
adb forward tcp:6100 tcp:7100

관련 링크

http://www.florescu.org/archives/2010/10/15/android-usb-connection-to-pc/
https://bitbucket.org/mgbckr/code-android-usb-socket-connection/overview


JAVA 소스

java androidusb.java 소스 (Eclipse로 실행)

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class androidusb {

    private Socket socket;
    private PrintWriter out;
    private Scanner sc;

    /**
     * Initialize connection to the phone
     *
     */
    public void initializeConnection(){
        //Create socket connection
        try{
            socket = new Socket("localhost", 10300);
            out = new PrintWriter(socket.getOutputStream(), true);
            //in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            sc = new Scanner(socket.getInputStream());

            // add a shutdown hook to close the socket if system crashes or exists unexpectedly
            Thread closeSocketOnShutdown = new Thread() {
                public void run() {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };

            Runtime.getRuntime().addShutdownHook(closeSocketOnShutdown);

        } catch (UnknownHostException e) {
            System.err.println("Socket connection problem (Unknown host)" + e.getStackTrace());
        } catch (IOException e) {
            System.err.println("Could not initialize I/O on socket " + e.getStackTrace());
        }
    }

    public static void main(String[] args) {

     androidusb t = new androidusb();
        t.initializeConnection();

        while(t.sc.hasNext()) {
        System.out.println(System.currentTimeMillis() + " / " + t.sc.nextLine());
        }
    }

}


APK 소스

MainActivity.java

package com.darts.androidusb;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Scanner;

public class MainActivity extends AppCompatActivity {
    public static final String TAG="Main";
    public static final int TIMEOUT=60;
    private ServerSocket server = null;
    private String connectionStatus = null;
    private Handler mHandler = null;
    public Socket client=null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.mHandler = new Handler();
        start();
    }
    public void start() {

        // Socket thread
        new Thread() {
            @Override
            public void run() {

                // initialize server socket
                try{
                    server = new ServerSocket(30300);
                    server.setSoTimeout(TIMEOUT * 1000);

                    Log.d(TAG, "Waiting for connection.");
                    //attempt to accept a connection
                    client = server.accept();
                    Log.d(TAG, "Accepted");

                    Globals.socketIn = new Scanner(client.getInputStream());
                    Globals.socketOut = new PrintWriter(client.getOutputStream(), true);
                } catch (SocketTimeoutException e) {
                    // print out TIMEOUT
                    connectionStatus="Connection has timed out! Please try again";
                    mHandler.post(showConnectionStatus);
                    Log.d(TAG, "Connection timeout");
                } catch (IOException e) {
                    Log.e(TAG, "" + e);
                } finally {
                    //close the server socket
                    try {
                        if (server!=null)
                            Log.d(TAG, "Closing server");
                        server.close();
                    } catch (IOException ec) {
                        Log.e(TAG, "Cannot close server socket" + ec);
                    }
                }

                if (client!=null) {
                    Log.d(TAG, "Connection was successful!");
                    Globals.connected = true;
                    // print out success
                    connectionStatus="Connection was successful!";
                    mHandler.post(showConnectionStatus);
                }
            }
        }.start();

        // Tx thread
        new Thread() {
            @Override
            public void run() {
                while(true){
                    while(Globals.connected) {
                        Log.d(TAG, "writing things");
                        Globals.socketOut.write("Time: " + System.currentTimeMillis() + "\n");
                        Globals.socketOut.flush();
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
    private Runnable showConnectionStatus = new Runnable() {
        public void run() {
            Toast.makeText(MainActivity.this, connectionStatus, Toast.LENGTH_SHORT).show();
        }
    };
}

Globals.java

package com.darts.androidusb;

/**
 * Created by darts on 2018-04-08.
 */


import java.io.PrintWriter;
import java.util.Scanner;

/**
 * Created by becker on 10.03.15.
 */
public class Globals {
    public static boolean connected = false;
    public static Scanner socketIn;
    public static Prin

AndroidManifesst.xml
권한 관련 에러시 internet 관련 권한을 추가해야 합니다.
<uses-permission android:name="android.permission.INTERNET" />

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.darts.androidusb">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>


소스 링크

https://drive.google.com/open?id=1bPt0GMz2OM777gYGqerBRGgTmNnBzPU6

실행 방법

0. PC와 USB 연결
1. APK실행시킴
2. adb에서 아래 명령 수행
   adb forward tcp:10300 tcp:30300
3. JAVA에서 cmd line 프로그램 실행

동작 화면

1초 단위로 시간 화면이 올라감
1523189615154 / Time: 1523189618906
1523189616158 / Time: 1523189619908
1523189617160 / Time: 1523189620911
1523189618161 / Time: 1523189621913
1523189619163 / Time: 1523189622915
1523189620165 / Time: 1523189623917
1523189621169 / Time: 1523189624919
1523189622171 / Time: 1523189625922
1523189623174 / Time: 1523189626925
1523189624177 / Time: 1523189627927


해당 소스는 가져온뒤 조금 변형하였습니다.
소스 분석은 정리해서 2탄에서 하도록 하겠습니다.















댓글 1개:

  1. [질문] 게시물 잘 보았습니다. 그런데 한가지 질문이 있습니다. ADB 소켓을 활용해 안드로이드 폰에서 메시지를 보내려 할때(SMS수신 등) TCP연결인 경우 android가 소켓 클라언트입장에서 PC 소켓서버측으로 연결을 수립하여 보내는 방식인데, ADB의 경우 android가 서버인지라 계속해서 PC클라이언트와 최초의 소켓 연결을 유지해야 하는것 처럼 보입니다. 제 생각이 맞는건지.. 그렇다면 android 서버에서 소켓연결은 유지가 되는 상태에서 SMS수신 이벤트 발생시 해당 msg를 Globals.socketOut.write할 수 있는건지요? SMS수신시 동작하는 onReceive() 함수에 socketOUT.write를 호출하면 가능한건가요? (global 함수니까?)

    답글삭제