1. 程式人生 > >一步步編寫一個AndroidStudio_NDK UDPClient 程式

一步步編寫一個AndroidStudio_NDK UDPClient 程式

1.配置NDK環境

1. 開啟一個專案,從選單欄中選擇 Tools > Android > SDK Manager2. 點選 SDK Tools 選項卡。
3. 勾選 LLDB,CMake 和 NDK

3.點選 Apply,然後點選 OK4.當安裝完成後,點選 Finish,然後點選 OK

2.建立一個支援 C/C++ 的新專案

1. Configure your new project
 選項中,勾選 Include C++ Support 選項。 2.點選 Next,後面的流程和建立普通的 Android studio 工程一樣。 3.Customize C++ Support 選項卡中:擇預設 CMake 設定的Toolchain Default 選項預設即可5.點選 “Finish”。

3.工程中新增C程式碼

切換到Android檢視

CPP資料夾會預設生成一個native-lib.cpp  
在這個檔案裡我們建立JNI方法,上連JAVA native
方法,下通我們需要的C/C++檔案
我們在這裡新增一個udpclient.c,並在native-lib.cpp包含該檔案

native-lib.cpp 

#include <jni.h>
#include <string>
#include "udpclient.c"
#include "base.h"


extern "C" {
JNIEXPORT void JNICALL
Java_org_udpclient_MainActivity_sendData(JNIEnv *env, jobject instance, jstring hostName_,
                                         jint portno) {
    const char *hostName = env->GetStringUTFChars(hostName_, 0);
    // TODO
    int portno_java = portno;
    LOGI("native 傳送 udp function");
    main_send(hostName, portno_java);
    LOGI("native 傳送 udp function finish");
    env->ReleaseStringUTFChars(hostName_, hostName);
}

}


udpclient.c檔案

//
// Created by pactera on 2016/12/2.
//

/*
 * udpclient.c - A simple UDP client
 * usage: udpclient <host> <port>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "base.h"
#include <pthread.h>

#define BUFSIZE 1024



int main_send(const char *hostname_java, int portno_java) {
    int sockfd, portno, n;
    int serverlen;
    struct sockaddr_in serveraddr;
    char buf[BUFSIZE];

    struct hostent *server;
    const char *hostname;

    hostname = hostname_java;
    portno = portno_java;

    /* socket: create the socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
        LOGE("ERROR opening socket");

    /* gethostbyname: get the server's DNS entry */
    server = gethostbyname(hostname);
    if (server == NULL) {
        LOGE("no such host as");
        return -1;
    }

    /* build the server's Internet address */
    bzero((char *) &serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    bcopy((char *)server->h_addr,
          (char *)&serveraddr.sin_addr.s_addr, server->h_length);
    serveraddr.sin_port = htons(portno);

    /* init message data*/
    strcpy(buf,"client send message");

    /* send the message to the server */
    serverlen = sizeof(serveraddr);
    n = (int)sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&serveraddr, serverlen);
    if (n < 0)
        LOGE("ERROR in sendto");
    LOGI("client send complete");




    n = (int)recvfrom(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&serveraddr, (socklen_t*)&serverlen);
    if (n < 0)
        LOGE("ERROR in recvfrom");
    return 0;
}

base.h檔案

#ifndef UDPCLIENT_BASE_H
#define UDPCLIENT_BASE_H

#endif //UDPCLIENT_BASE_H
#include <android/log.h>
#define TAG "yueguang" // 這個是自定義的LOG的標識
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定義LOGD型別
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定義LOGI型別
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定義LOGW型別
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定義LOGE型別



cmakelist中參考下面的格式進行新增,別忘記換行,在小括號的包裹範圍內


5.使用JNI呼叫native方法

Java程式碼中宣告native方法
    public native void sendData(String hostName,int portno);
 
Alt+Enter便可以在native-lib檔案中生成對應的Jni方法,我們只要編寫方法體就可以了

建立的JNI方法應該在extern "C" {....}包裹範圍內,否則呼叫的時候會出錯

Native method not found

JNIEXPORT void JNICALL
Java_org_udpclient_MainActivity_sendData(JNIEnv *env, jobject instance, jstring hostName_,
                                         jint portno) {
    const char *hostName = env->GetStringUTFChars(hostName_, 0);
    // TODO
    int portno_java = portno;
    LOGE("native 傳送 udp function");
    main_send(hostName, portno_java);

    env->ReleaseStringUTFChars(hostName_, hostName);
}

6.使用Android Log系統

新建個base..h把下面的程式碼拷貝進去
 
#include <android/log.h>
#define TAG "yueguang" // 這個是自定義的LOG的標識
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定義LOGD型別
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定義LOGI型別
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定義LOGW型別
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定義LOGE型別
 然後在需要使用AndroidLog系統的.c或.cpp檔案中#include "base.h" 
//使用方法
LOGE("native 傳送 udp function");

======================================================== 致此大工告成,執行即可