web-dev-qa-db-fra.com

Comment créer une connexion Socket sous Android?

J'ai une application dans laquelle j'ai besoin de créer une connexion socket. Mon exigence est la suivante: une fois ma connexion de socket établie, elle doit être active jusqu'à ce que je la ferme personnellement. Et toutes les 3 minutes, je dois envoyer des paquets de données à l’autre bout. Quelqu'un peut-il me fournir des exemples de code qui m'aideront à le faire?

39
Nilanchal

Les connexions de socket dans Android sont identiques à celles de Java: http://www.Oracle.com/technetwork/Java/socket-140484.html

Les choses que vous devez savoir:

  1. Si le téléphone se met en veille, votre application ne sera plus exécutée, de sorte que la prise expirera éventuellement. Vous pouvez empêcher cela avec le verrouillage de réveil. Cela consommera énormément la batterie des appareils - je sais que je n'utiliserais pas cette application.
  2. Si vous le faites constamment, même lorsque votre application n'est pas active, vous devez utiliser le service.
  3. Les activités et les services peuvent être supprimés à tout moment par le système d'exploitation, en particulier s'ils font partie d'une application inactive.

Jetez un coup d'œil à AlarmManager, si vous avez besoin d'une exécution programmée de votre code.

Devez-vous exécuter votre code et recevoir des données même si l’utilisateur n’utilise plus l’application (c’est-à-dire que l’application est inactive)?

53
Peter Knego

Ici, dans cet article, vous trouverez le code détaillé permettant d’établir une connexion entre des appareils ou entre deux applications d’un même mobile.

Vous devez créer deux applications pour tester le code ci-dessous.

Dans les deux applications fichier manifeste, ajoutez l'autorisation ci-dessous.

<uses-permission Android:name="Android.permission.INTERNET" />

1er code de l'application: socket client

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <TableRow
        Android:id="@+id/tr_send_message"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:gravity="center"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true"
        Android:layout_alignParentTop="true"
        Android:layout_marginTop="11dp">

        <EditText
            Android:id="@+id/edt_send_message"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:layout_marginRight="10dp"
            Android:layout_marginLeft="10dp"
            Android:hint="Enter message"
            Android:inputType="text" />

        <Button
            Android:id="@+id/btn_send"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_marginRight="10dp"
            Android:text="Send" />
    </TableRow>

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true"
        Android:layout_below="@+id/tr_send_message"
        Android:layout_marginTop="25dp"
        Android:id="@+id/scrollView2">

        <TextView
            Android:id="@+id/tv_reply_from_server"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:orientation="vertical" />
    </ScrollView>
</RelativeLayout>

MainActivity.Java

import Android.os.Bundle;
import Android.os.Handler;
import Android.support.v7.app.AppCompatActivity;
import Android.view.View;
import Android.widget.Button;
import Android.widget.EditText;
import Android.widget.TextView;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.OutputStream;
import Java.io.PrintWriter;
import Java.net.Socket;

/**
 * Created by Girish Bhalerao on 5/4/2017.
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView mTextViewReplyFromServer;
    private EditText mEditTextSendMessage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button buttonSend = (Button) findViewById(R.id.btn_send);

        mEditTextSendMessage = (EditText) findViewById(R.id.edt_send_message);
        mTextViewReplyFromServer = (TextView) findViewById(R.id.tv_reply_from_server);

        buttonSend.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.btn_send:
                sendMessage(mEditTextSendMessage.getText().toString());
                break;
        }
    }

    private void sendMessage(final String msg) {

        final Handler handler = new Handler();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    //Replace below IP with the IP of that device in which server socket open.
                    //If you change port then change the port number in the server side code also.
                    Socket s = new Socket("xxx.xxx.xxx.xxx", 9002);

                    OutputStream out = s.getOutputStream();

                    PrintWriter output = new PrintWriter(out);

                    output.println(msg);
                    output.flush();
                    BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
                    final String st = input.readLine();

                    handler.post(new Runnable() {
                        @Override
                        public void run() {

                            String s = mTextViewReplyFromServer.getText().toString();
                            if (st.trim().length() != 0)
                                mTextViewReplyFromServer.setText(s + "\nFrom Server : " + st);
                        }
                    });

                    output.close();
                    out.close();
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();
    }
}

2nd App Code - Server Socket

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <Button
        Android:id="@+id/btn_stop_receiving"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="STOP Receiving data"
        Android:layout_alignParentTop="true"
        Android:enabled="false"
        Android:layout_centerHorizontal="true"
        Android:layout_marginTop="89dp" />

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_below="@+id/btn_stop_receiving"
        Android:layout_marginTop="35dp"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true">

        <TextView
            Android:id="@+id/tv_data_from_client"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:orientation="vertical" />
    </ScrollView>

    <Button
        Android:id="@+id/btn_start_receiving"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="START Receiving data"
        Android:layout_alignParentTop="true"
        Android:layout_centerHorizontal="true"
        Android:layout_marginTop="14dp" />
</RelativeLayout>

MainActivity.Java

import Android.os.Bundle;
import Android.os.Handler;
import Android.support.v7.app.AppCompatActivity;
import Android.view.View;
import Android.widget.Button;
import Android.widget.TextView;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.PrintWriter;
import Java.net.ServerSocket;
import Java.net.Socket;

/**
 * Created by Girish Bhalerao on 5/4/2017.
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    final Handler handler = new Handler();

    private Button buttonStartReceiving;
    private Button buttonStopReceiving;
    private TextView textViewDataFromClient;
    private boolean end = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buttonStartReceiving = (Button) findViewById(R.id.btn_start_receiving);
        buttonStopReceiving = (Button) findViewById(R.id.btn_stop_receiving);
        textViewDataFromClient = (TextView) findViewById(R.id.tv_data_from_client);

        buttonStartReceiving.setOnClickListener(this);
        buttonStopReceiving.setOnClickListener(this);

    }

    private void startServerSocket() {

        Thread thread = new Thread(new Runnable() {

            private String stringData = null;

            @Override
            public void run() {

                try {

                    ServerSocket ss = new ServerSocket(9002);

                    while (!end) {
                        //Server is waiting for client here, if needed
                        Socket s = ss.accept();
                        BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
                        PrintWriter output = new PrintWriter(s.getOutputStream());

                        stringData = input.readLine();
                        output.println("FROM SERVER - " + stringData.toUpperCase());
                        output.flush();

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        updateUI(stringData);
                        if (stringData.equalsIgnoreCase("STOP")) {
                            end = true;
                            output.close();
                            s.close();
                            break;
                        }

                        output.close();
                        s.close();
                    }
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        });
        thread.start();
    }

    private void updateUI(final String stringData) {

        handler.post(new Runnable() {
            @Override
            public void run() {

                String s = textViewDataFromClient.getText().toString();
                if (stringData.trim().length() != 0)
                    textViewDataFromClient.setText(s + "\n" + "From Client : " + stringData);
            }
        });
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_start_receiving:

                startServerSocket();
                buttonStartReceiving.setEnabled(false);
                buttonStopReceiving.setEnabled(true);
                break;

            case R.id.btn_stop_receiving:

                //stopping server socket logic you can add yourself
                buttonStartReceiving.setEnabled(true);
                buttonStopReceiving.setEnabled(false);
                break;
        }
    }
}
15
Girish Bhalerao

Exemple d'application de serveur de socket simple

J'ai déjà posté un exemple de client à l'adresse suivante: https://stackoverflow.com/a/35971718/895245 , voici donc un exemple de serveur.

Cet exemple d'application exécute un serveur qui renvoie un chiffrement ROT-1 de l'entrée.

Vous devrez ensuite ajouter un bouton Exit ainsi que des délais d'attente, mais cela devrait vous aider à démarrer.

Pour jouer avec:

Les sockets Android sont les mêmes que ceux de Java, sauf que nous avons des problèmes d'autorisation.

src/com/cirosantilli/Android_cheat/socket/Main.Java

package com.cirosantilli.Android_cheat.socket;

import Android.app.Activity;
import Android.app.IntentService;
import Android.content.Intent;
import Android.os.Bundle;
import Android.util.Log;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.PrintStream;
import Java.net.ServerSocket;
import Java.net.Socket;

public class Main extends Activity {
    static final String TAG = "AndroidCheatSocket";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(Main.TAG, "onCreate");
        Main.this.startService(new Intent(Main.this, MyService.class));
    }

    public static class MyService extends IntentService {
        public MyService() {
            super("MyService");
        }
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d(Main.TAG, "onHandleIntent");
            final int port = 12345;
            ServerSocket listener = null;
            try {
                listener = new ServerSocket(port);
                Log.d(Main.TAG, String.format("listening on port = %d", port));
                while (true) {
                    Log.d(Main.TAG, "waiting for client");
                    Socket socket = listener.accept();
                    Log.d(Main.TAG, String.format("client connected from: %s", socket.getRemoteSocketAddress().toString()));
                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    PrintStream out = new PrintStream(socket.getOutputStream());
                    for (String inputLine; (inputLine = in.readLine()) != null;) {
                        Log.d(Main.TAG, "received");
                        Log.d(Main.TAG, inputLine);
                        StringBuilder outputStringBuilder = new StringBuilder("");
                        char inputLineChars[] = inputLine.toCharArray();
                        for (char c : inputLineChars)
                            outputStringBuilder.append(Character.toChars(c + 1));
                        out.println(outputStringBuilder);
                    }
                }
            } catch(IOException e) {
                Log.d(Main.TAG, e.toString());
            }
        }
    }
}

Nous avons besoin de Service ou d’une autre méthode d’arrière-plan, sinon: Comment puis-je réparer Android.os.NetworkOnMainThreadException?

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
      package="com.cirosantilli.Android_cheat.socket"
      Android:versionCode="1"
      Android:versionName="1.0">
    <uses-sdk Android:minSdkVersion="22" />
    <uses-permission Android:name="Android.permission.INTERNET" />
    <application Android:label="AndroidCheatsocket">
        <activity Android:name="Main">
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN" />
                <category Android:name="Android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service Android:name=".Main$MyService" />
    </application>
</manifest>

Il faut ajouter: <uses-permission Android:name="Android.permission.INTERNET" /> ou sinon: exception Java socket IOException - permission refusée

Sur GitHub avec un build.xml: https://github.com/cirosantilli/Android-cheat/tree/92de020d0b708549a444ebd9f881de7b240b3fbc/socket