반응형

이전의 Java 포스팅을 이어가야하는데.. 하면서 깜빡깜빡하네요. 조만간 이어가도록 하겠습니다.

여튼 이번엔 프로그래머나 개발자라면 기본적으로 다루게 될 Java API와 관련하여 자신의 Local에서 Socket을 이용한 서버와 클라이언트의 Data를 주고받는 부분을 살펴보려 합니다.


[SocketServer.java]

/**
* Created by 진우 on 2016-07-09.
*/
public class SocketServer {
public static void main(String[] args) {
SocketServer serv = new SocketServer();
serv.startServer();
}

public void startServer() {
ServerSocket sockserv = null;
Socket sockcli = null;

try {
sockserv = new ServerSocket(9629);
while(true) {
System.out.println("Server is waiting for request.");

sockcli = sockserv.accept();
System.out.println("Server Socket is Accepted!");

InputStream stream = sockcli.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String data = null;
StringBuilder receiveData = new StringBuilder();
while((data = in.readLine()) != null) {
receiveData.append(data);
}
System.out.println("Receive Data :"+receiveData);
in.close();
stream.close();
sockcli.close();
if(receiveData.toString().equals("End of TEST")) {
System.out.println("Stop Socket Server!");
break;
}
System.out.println("------");
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(sockserv != null) {
try {
sockserv.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}


먼저 서버에서는 Socket을 서버, 클라이언트용으로 두 개 만들어줍니다.

그리고 StartServer() 에서 포트를 9629로 하여 로컬에서 실행되도록 합니다.

while(true)문을 이용하여 Client로부터 End of Test 라는 메시지가 올 때까지 계속 실행되도록 합니다.

socket accept를 통해 클라이언트로부터 data를 받아들이고, data가 null일 때까지 계속 while문으로 받아서 receiveData에 append해줍니다.

그리고 다 받아서 while문을 빠져나오면, socket과 stream을 close 해주어 마무리해줍니다.


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

[SocketClient.java]

/**
* Created by 진우 on 2016-07-09.
*/
public class SocketClient {
public static void main(String[] args) {
SocketClient cli = new SocketClient();
cli.sendSocket();
}

public void sendSocket() {
for(int loop = 1; loop <= 5; loop++) {
sendSocketData("Just Test Client - Server (" + loop + ")");
}
sendSocketData("End of TEST");
}

public void sendSocketData(String data) {
Socket sock = null;
try {
System.out.println("Client is Connecting");

sock = new Socket("127.0.0.1", 9629);
System.out.println("Client:Connect status = "+sock.isConnected());
Thread.sleep(1500);
OutputStream stream = sock.getOutputStream();
BufferedOutputStream out = new BufferedOutputStream(stream);
byte[] bytes = data.getBytes();
out.write(bytes);

System.out.println("Client:Send data");
out.close();

} catch(Exception e) {
e.printStackTrace();
} finally {
if(sock != null) {
try {
sock.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
}


Client에서는 for문을 이용하여 서버에 5번 Data를 보내게 됩니다. 그리고 마지막으로 End of Test 라는 메시지를 보내어 서버가 이 메시지를 받았을 때 종료되도록 합니다.

sendSocketData()에서는 Socket을 생성하여 Local서버(127.0.0.1)에 9629포트에 보내도록 하고, Socket의 현재 상태(연결 되어 있는지 - sock.isConnected() 이용) 를 Client에서 출력해줍시다.

간격은 Thread를 이용하여 1.5초(1500mllis)로 하고, OutputStream을 이용하여 서버에 data를 보내줍니다.

그 후, client에서 Send data 메시지를 출력해 준 후, stream을 닫아줍니다.


network통신에서는 try - catch 문을 꼭 이용하여 Exception이 발생 했을 시를 체크해줍시다.



원래 Eclipse를 애용했었는데 요즘은 시대에 맞게 Intellij를 되도록 사용하려 합니다.

아직은 조금 서툰부분도 많습니다만 빨리 적응해야겠습니다.

반응형

WRITTEN BY
SiriusJ

,
반응형

날씨 API는 많이 지원해주고 있습니다.

기상청API나 기타 다른 API들도 있지만 그 중에서도 저는 이번에 Openweather라는 날씨 API를 이용해보려 합니다.

(저는 Node.js를 이용한 서버에서 JSON 형식의 데이터로 파싱해오도록 하겠습니다.)


먼저 http://www.openweathermap.org/ 으로 접속해봅시다.


상단 메뉴에서 API를 클릭하면 아래와 같이 보실 수 있습니다.

먼저, API Key를 클릭하여 해당 페이지로 이동하고, Sign up을 하여 API KEY를 얻어줍시다.

(API를 사용하기 위해 얻어진 API KEY는 꼭 기억해주셔야 합니다!)


이후에 Current weather data 의 API doc을 클릭하여 문서를 참조하면, API를 이용하는 부분에 대한 설명을 확인할 수 있습니다. API를 이용하는 중요한 정보들이 대부분 이곳에 있으므로 자주 참조하게 될 것입니다.


만약, API KEY를 얻었다면, 아래에서 APPID=  다음에 받으신 API KEY를 그대로 넣어서 브라우저에서 접속해보면, 현재 서울의 기상정보를 JSON형식의 데이터로 바로 확인할 수 있습니다.

http://api.openweathermap.org/data/2.5/weather?q=Seoul&mode=json&units=metric&APPID=(당신의KEY를넣어주세요.)

(크롬 브라우저에서의 URL을 이용한 날씨정보 확인 - 참고)

여기까지, 만약 브라우저에서 해당 url로 접속했을 때 다음과 같이 데이터가 보이지 않는다면 API KEY가 잘못되었을 확률이 높으므로 다시한번 확인해줍시다!


만약, 잘 확인이 되었다면, 이제 자신의 서버에서 직접 서버에 요청을 보내어 위와 같은 데이터를 가져와야 합니다.

아래 코드에서 URL에 APPID에 자신의 APPKEY만 수정해서 넣어주시면 됩니다.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

[testServer.js]

var http = require('http');

var express = require('express');


var app = express();

var server = http.createServer(app);


app.use(express.static(__dirname + "/index"));


app.get('/', function(req, res, err) {

res.send(200, "Success");

});


//(Temp variable), for Weather Information

var cityname, citylon, citylat, cityweather, weatherid, weathermain, citytemp, cityhumi, citytemp_min, citytemp_max, citywind, cityclouds;

//var weatherArr = new Array();            아래에서 변수에 저장하는 대신 배열을 이용하셔도 됩니다.


//(Temp variable2), for Today weather Information

var citytime9, citytemp9, cityhumi9, citymain9, cityid9;

var citytime12, citytemp12, cityhumi12, citymain12, cityid12;

var citytime15, citytemp15, cityhumi15, citymain15, cityid15;

var citytime18, citytemp18, cityhumi18, citymain18, cityid18;

var citytime21, citytemp21, cityhumi21, citymain21, cityid21;


//현재시간에 맞는 서울의 날씨정보를 얻어오는 function입니다.

function currentInfo() {

var urlCurr = 'http://api.openweathermap.org/data/2.5/weather?q=Seoul&mode=json&units=metric&APPID=당신의API키를넣어주세요.';


http.get(urlCurr, function(res) {

var body = '';

res.on('data', function(chunk) {

body += chunk.toString();

});


res.on('end', function() {

try {

var fbResponse = JSON.parse(body);    

//JSON형식으로 추출하여 fbResponse에 담아주고, 아래에서 각각의 변수들에 해당 데이터를 저장해 줍니다.


cityname = fbResponse.name;        //도시 이름

citylon = fbResponse.coord.lon;      //도시의 좌표(경도,위도)

citylat = fbResponse.coord.lat;

weatherid = fbResponse.weather[0].id;

weathermain = fbResponse.weather[0].main;

citytemp = fbResponse.main.temp;

cityhumi = fbResponse.main.humidity;

citytemp_min = fbResponse.main.temp_min;

citytemp_max = fbResponse.main.temp_max;

citywind = fbResponse.wind.speed;

cityclouds = fbResponse.clouds.all;

//아래에서 로그를 콘솔에 찍어봄으로써 데이터가 제대로 추출되었는지 확인해봅니다.

console.log("cityname=", cityname);

console.log("weatherid=", weatherid);

console.log("weathermain=", weathermain);

console.log("citytemp=", citytemp);

} catch (e) {

console.log(e);

/* 가끔씩, 한번에 못 받아올때가 있습니다. (아마 서버쪽의 오류인듯 싶습니다.) 그래서 만약 못받아 올 때를 대비하여 try-catch구문을 이용하여 catch에서 currentInfo()를 한번 더 선언해줌으로써 오류가 났을 때에는 다시 한번 요청을 해서 받아오게 됩니다. */

currentInfo();

}

});

res.on('error', function(e) {

console.log("Got an error: ", e);

});

});

}

//Active Once. (First) - 서버를 실행할 때, currentInfo()를 불러주어 아래에서 API를 처음 call하게 됩니다.

currentInfo();

//After, repeat Active (After), - (period 1Hour, for update) - 이후에, 1시간 간격으로 Interval을 통하여 지속적으로 실행해줍니다.

var curi = setInterval(currentInfo, 3600000);



/*아래의 todayInfo()는 현재 시간에 따른 날씨정보 뿐만 아니라 오늘의 날씨정보를 얻기 위하여 추가로 작성해보았습니다.*/

// request for today(forecast) -  위의 currentInfo()와 같은 내용이므로 자세한 설명은 생략하도록 하겠습니다.

function todayInfo() {

var urltoday = 'http://api.openweathermap.org/data/2.5/forecast?q=Seoul&mode=json&units=metric&APPID=당신의API키를넣어주세요.';

http.get(urltoday, function(res) {

var body2 = '';

res.on('data', function(chunk2) {

body2 += chunk2.toString();

});


res.on('end', function() {

try {

var fbResponse2 = JSON.parse(body2);


citytemp9 = fbResponse2.list[0].main.temp;

cityhumi9 = fbResponse2.list[0].main.humidity;

cityid9 = fbResponse2.list[0].weather[0].id;

citymain9 = fbResponse2.list[0].weather[0].main;

citytemp12 = fbResponse2.list[1].main.temp;

cityhumi12 = fbResponse2.list[1].main.humidity;

cityid12 = fbResponse2.list[1].weather[0].id;

citymain12 = fbResponse2.list[1].weather[0].main;


citytemp15 = fbResponse2.list[2].main.temp;

cityhumi15 = fbResponse2.list[2].main.humidity;

cityid15 = fbResponse2.list[2].weather[0].id;

citymain15 = fbResponse2.list[2].weather[0].main;


citytemp18 = fbResponse2.list[3].main.temp;

cityhumi18 = fbResponse2.list[3].main.humidity;

cityid18 = fbResponse2.list[3].weather[0].id;

citymain18 = fbResponse2.list[3].weather[0].main;


citytemp21 = fbResponse2.list[4].main.temp;

cityhumi21 = fbResponse2.list[4].main.humidity;

cityid21 = fbResponse2.list[4].weather[0].id;

citymain21 = fbResponse2.list[4].weather[0].main;

console.log("citymain in 9(Morning)=", citymain9);

console.log("citymain in 21(Evening)=", citymain9);

} catch (e) {

console.log(e);

todayInfo();

}

});

res.on('error', function(e) {

console.log("Got an error: ", e);

});

});

}

todayInfo();

var todayI = setInterval(todayInfo, 86400000); //86400sec = 1 day,(period 1day, for update)


server.listen(8888, function(req, res) {

console.log("server running on 8888.");

});


///////////////////////////////////////////////////////////////////////////////////////////////////////////////

이해를 돕기위하여 변수를 무지막지하게 선언했습니다...

변수들 대신에 배열을 만들어서 원하는 데이터를 추출하셔도 됩니다.

ex) var weatherArr[];

와 같이 선언 후, 배열에 파싱한 값을 넣어주셔도 됩니다.


이상으로, GET방식으로 서버에 요청하여 JSON 형식의 데이터를 받아오는 모습이었습니다.


위 코드를 작성하고 실행시키면, 아래와 같이 데이터가 콘솔에 찍히는 것을 확인 할 수 있습니다.

(워낙에 설명이 빈약해서.. 참고 설명으로 cityname은 url에서 요청한 도시에 대한 이름이, weatherid는 Open weather API에서 지정한 날씨Code가, weathermain은 날씨의 정보가, citytemp는 도시의 온도 정보 입니다.!)


보다 구체적인 데이터들을 확인하고, 파싱하고 싶다면 문서를 참조하시는걸 추천드립니다! 또한 서울 뿐만이 아니라 URL에서 Seoul 대신 다른 도시로 바꿔주어 해당 도시에 대한 정보를 얻을 수 있습니다. Open weather에서 제공하는 도시의 목록은 http://www.openweathermap.org/current 부분을 열심히 뒤져보시면 어딘가에 도시 Sample들에 대한 파일이 있을겁니다. 받으셔서 도시들 목록을 확인하시면 됩니다. (우리나라 뿐만 아니라 세계 각국의 도시들도 무지 많습니다.)

http://bulk.openweathermap.org/sample/ )

반응형

'Programming > Node.js' 카테고리의 다른 글

Node.js 로 서버 구축  (0) 2016.06.26

WRITTEN BY
SiriusJ

,
반응형

[MainActivity.java]

public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}


[activity_main.xml]

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

<TextView
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Type here:"/>

<EditText
android:id="@+id/entry"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background"
android:textColor="#000"
android:layout_below="@id/label"/>

<Button
android:id="@+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/entry"
android:layout_alignParentRight="true"
android:layout_marginLeft="10dip"
android:text="OK" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/ok"
android:layout_alignTop="@id/ok"
android:text="Cancel" />

</RelativeLayout>


반응형

WRITTEN BY
SiriusJ

,
반응형

Node.js 를 이용하여 서버를 간단하게 생성해보도록 하겠습니다.


[testServer.js]

var http = require('http');

var express = require('express');


var app = express();

var server = http.createServer(app);


app.use(express.static(__dirname + "/index"));


app.get('/', function(req, res, err) {

res.send(200, "Success");

});


server.listen(8888, function(req, res) {

console.log("server running on 8888.");

});

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

[index.html]

<!DOCTYPE html>

<html>

<head>

<meta charset="EUC-KR">

<title>Test Page</title>

</head>

<body>

<h1>Hello, It is Test Page!</h1>

</body>

</html>

반응형

WRITTEN BY
SiriusJ

,
반응형

본 포스팅에서 네이버 음성인식API를 이용하는데에 필요한 코드는

MainActivity.java, NaverTalkActivity.java, NaverRecognizer.java, AudioWriterPCM.java, activity_main.xml, activity_talk.xml 입니다.

(포스팅에서 다루는 저의 경우이니, 사용하시는 분에 따라서 변경될 수 있겠습니다.)

///////////////////////////////////////////////////////////////////////////////////////////////////

지난 포스팅에 이어 이제 NaverTalkActivity 를 만들어줄 차례입니다. 군데군데 수정만 해주시면 될것입니다.


이전에 다운받았던 SDK로 이동하여, 

naverspeech-sdk-android-master\naverspeech-sdk-android-master\sample\NaverspeechClient-android-studio\app\src\main\java\com\naver\naverspeech\client 로 이동하면 아래와 같이 3가지 소스가 있습니다.

( MainActivity의 내용을 조금 수정하여 NaverTalkActivity를 만들어 줄 것입니다. 이 부분은 아래에서! )

우선, utils의 내용은 같으므로, 본인의 안드로이드 스튜디오에서 utils 패키지를 만들어 준 후, AudioWriterPCM.java 를 그대로 옮겨줍니다. 패키지 이름에 계속 신경써줍시다.

그리고, NaverRecognizer.java 또한 같으므로, 그대로 본인의 프로젝트로 옮겨줍니다.

지난 포스팅에서 저는 naverTalk라는 패키지를 하나 만들어서 그 안에 넣어주었으므로 그렇게 따라하시면 됩니다.

(만약, MainActivity와 같은 패키지에 하셔도 상관없지만, 이전 포스팅에서 Manifest에서 activity의 경로는 수정해주셔야 됩니다.)

naverTalk라는 패키지에 이제 NaverTalkActivity.java 를 생성해줍시다.


/////////////////////////////////////////////////////////////////////////////////

[NaverTalkActivity.java]

import java.lang.ref.WeakReference;

import com.naver.naverspeech.client.utils.AudioWriterPCM;

import com.naver.speech.clientapi.SpeechConfig;

//다른 import 또한 추가해주시면 됩니다.


public class MainActivity extends Activity {

private static final String CLIENT_ID = "Your Client ID"; // "내 애플리케이션"에서 Client ID를 확인해서 이곳에 적어주세요.

private static final SpeechConfig SPEECH_CONFIG = SpeechConfig.OPENAPI_KR; // or SpeechConfig.OPENAPI_EN


private RecognitionHandler handler;

private NaverRecognizer naverRecognizer;

private TextView txtResult;

private Button btnStart;

private String mResult;

private AudioWriterPCM writer;

private boolean isRunning;


// Handle speech recognition Messages.

private void handleMessage(Message msg) {

switch (msg.what) {

case R.id.clientReady:

// Now an user can speak.

txtResult.setText("Connected");

writer = new AudioWriterPCM(

Environment.getExternalStorageDirectory().getAbsolutePath() + "/NaverSpeechTest");

writer.open("Test");

break;


case R.id.audioRecording:

writer.write((short[]) msg.obj);

break;


case R.id.partialResult:

// Extract obj property typed with String.

mResult = (String) (msg.obj);

txtResult.setText(mResult);

break;


case R.id.finalResult:

// Extract obj property typed with String array.

// The first element is recognition result for speech.

String[] results = (String[]) msg.obj;

mResult = results[0];

txtResult.setText(mResult);

break;


case R.id.recognitionError:

if (writer != null) {

writer.close();

}


mResult = "Error code : " + msg.obj.toString();

txtResult.setText(mResult);

btnStart.setText(R.string.str_start);

btnStart.setEnabled(true);

isRunning = false;

break;


case R.id.clientInactive:

if (writer != null) {

writer.close();

}


btnStart.setText(R.string.str_start);

btnStart.setEnabled(true);

isRunning = false;

break;

}

}


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_talk);


txtResult = (TextView) findViewById(R.id.txt_result);

btnStart = (Button) findViewById(R.id.btn_start);


handler = new RecognitionHandler(this);

naverRecognizer = new NaverRecognizer(this, handler, CLIENT_ID, SPEECH_CONFIG);


btnStart.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

if (!isRunning) {

// Start button is pushed when SpeechRecognizer's state is inactive.

// Run SpeechRecongizer by calling recognize().

mResult = "";

txtResult.setText("Connecting...");

btnStart.setText(R.string.str_listening);

isRunning = true;


naverRecognizer.recognize();

} else {

// This flow is occurred by pushing start button again

// when SpeechRecognizer is running.

// Because it means that a user wants to cancel speech

// recognition commonly, so call stop().

btnStart.setEnabled(false);


naverRecognizer.getSpeechRecognizer().stop();

}

}

});

}


@Override

protected void onResume() {

super.onResume();

// initialize() must be called on resume time.

naverRecognizer.getSpeechRecognizer().initialize();


mResult = "";

txtResult.setText("");

btnStart.setText(R.string.str_start);

btnStart.setEnabled(true);

}


@Override

protected void onPause() {

super.onPause();

// release() must be called on pause time.

naverRecognizer.getSpeechRecognizer().stopImmediately();

naverRecognizer.getSpeechRecognizer().release();

isRunning = false;

}


// Declare handler for handling SpeechRecognizer thread's Messages.

static class RecognitionHandler extends Handler {

private final WeakReference<MainActivity> mActivity;


RecognitionHandler(MainActivity activity) {

mActivity = new WeakReference<MainActivity>(activity);

}


@Override

public void handleMessage(Message msg) {

MainActivity activity = mActivity.get();

if (activity != null) {

activity.handleMessage(msg);

}

}

}

}


/////////////////////////////////////////////////////////////////////////////////

위에서, NaverTalkActivity.java를 만들어주었다면. 이제 onCreate에서 해당 레이아웃을 꾸며주어 버튼을 클릭했을 때에, 음성인식을 받도록 기능을 구현하게 합니다.

activity_talk.xml의 소스는 간단합니다. 클릭할 버튼 하나와, 음성인식한 텍스트를 보여줄 TextView 하나만 있으면 됩니다.


[activity_talk.xml]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.naver.recognition.client.MainActivity" >


    <Button

        android:id="@+id/btn_start"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:text="@string/str_start" />


    <TextView

        android:id="@+id/txt_result"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@id/btn_start"

        android:layout_centerHorizontal="true"

        android:singleLine="false" />

</LinearLayout>



/////////////////////////////////////////////////////////////////////////////////

그리고, 이제 본 애플리케이션의 MainActivity와 activity_main.xml 을 꾸며봅시다!

MainActivity에서 임의의 버튼을 클릭했을 때, NaverTalkActivity로 넘어가도록 할 것입니다.


[activity_main.xml]

기본으로 생성되어져 있는 레이아웃 안에 button만 하나 추가해줍시다.

<Button

                android:id="@+id/btn_voice"

                android:drawableLeft="@android:drawable/ic_btn_speak_now"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:layout_gravity="center"

                android:gravity="center"

                android:textSize="10dp"

                android:text="음성 제어">

</Button>

/////////////////////////////////////////////////////////////////////////////////

[MainActivity.java]

public class MainActivity extends Activity {

private Button voiceBtn;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

voiceBtn = (Button)findViewById(R.id.btn_voice);


voiceBtn.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                Intent intent = new Intent(MainActivity.this, NaverTalkActivity.class);

                startActivity(intent);

            }

        });

}

}


이와 같이 MainActivity.java 를 구성하게 되면 마무리 되어집니다.

간단하게 보이고자 레이아웃을 매우 간단하게 꾸몄으니, 차후 레이아웃 디자인은 각자 예쁘게 꾸미시면 되겠습니다.

사실 네이버 음성인식API에 대한 부분은 워낙 코드도 간단하고 쉬운데다 가이드도 이해하기 쉽게 되어있어서 그대로 따라하셔도 초보자라도 30분~1시간이면 바로 테스트해볼 수 있으실 겁니다.

반응형

WRITTEN BY
SiriusJ

,
반응형

오늘은 네이버에서 제공하는 음성인식 API를 이용해보도록 하겠습니다.

아직은 Beta버전이지만 인식은 무리없이 잘 되는 것 같습니다.


자세한 API이용 설명은 개발가이드에서 제공해주는 https://developers.naver.com/docs/labs/vrecog 를 참고하셔도 금방 할 수 있으실 것입니다.


먼저 https://developers.naver.com/products/vrecog 에 네이버 개발자 센터에서 음성인식(Beta)를 선택하여 네이버에서 제공하는 음성인식API를 이용해봅시다. 

현재는 한국어와 영어를 제공해주고 있으며, 하루에 1000개까지 처리가 가능하다고 합니다.

-> 화면에서 오픈 API이용 신청을 클릭합니다.


애플리케이션 이름을 자유롭게 적어주시고, 카테고리를 설정하신 후, 음성인식API를 사용하기 위해 비로그인 오픈API 를 선택합니다. 

또한 다른 API(지도, 검색, 음성합성 등) 를 사용하고 싶다면, 추가적으로 선택해주시면 됩니다.


저는 안드로이드 스튜디오를 이용하여 애플리케이션을 제작 후, 네이버음성인식을 테스트해보고자 합니다.

따라서 안드로이드 스튜디오에서 처음 프로젝트를 만들 때, 입력한 패키지 이름을 이곳에 적어주시면 됩니다.

** 반드시 본인의 애플리케이션 패키지 이름과 동일하게 해주어야 합니다. ** - 패키지이름정도는 기억해줍시다~

다음으로 동의에 체크해 준 후, 등록하기를 눌러줍니다.


화면처럼, Client ID와 Client Secret 키가 생성된 것을 확인할 수 있습니다. 기억해주세요.


이제, SDK를 다운받아야 합니다. https://github.com/naver/naverspeech-sdk-android 이곳에 들어가시면 아래와 같은 화면에서, 초록색버튼 Clone or Download 를 클릭합시다.

Download ZIP 을 선택하여 코드를 다운받고, 압축을 풀어줍니다.


해당 폴더에 들어가서 sample로 이동하시면 위 화면으로 개발툴이 android-studio와 eclipse 로 나뉩니다. 

저는 Android Studio를 이용하기 때문에 해당 디렉토리로 이동합니다.

이동하셔서 바로 아래의 build.gradle 코드를 (본인의 Android Studio 툴 내에 있는 build.gradle)에 추가해줍니다.


다음으로 app 디렉토리로 이동하여 build.gradle에 있는 아래 코드를 (본인의 Android studio툴 내에서 기존에 존재하는 app-> build.gradle 파일에다가) 중복되는 부분을 제외한 나머지 코드만 추가해주면 됩니다.


그리고, 현 디렉토리(\naverspeech-sdk-android-master\naverspeech-sdk-android-master\sample\NaverspeechClient-android-studio\app) 에 build.gradle 외에 libs 라는 폴더도 있을 것입니다.

그대로 자신의 안드로이드 스튜디오에서 생성한 프로젝트의 똑같은 디렉토리에 그대로 폴더 자체를 복사하여 붙여넣어 줍니다. (libs에는 jar 파일이 들어있습니다.)


위까지 진행 하셨으면 이제 src->main 폴더로 이동하여 jniLibs 라는 폴더 또한 자신의 프로젝트의 해당 디렉토리에 복붙해줍니다.


//////////////////////////////////

이제는 코드에서 처리하도록 할 차례입니다. 먼저 Manifest에서 아래와 같이 작성해주면 됩니다. package=" " 에는 위에서 네이버 개발자센터에서 음성인식API를 등록할 때 설정해주었던 패키지 이름을 적어주시면 됩니다. 자신의 프로젝트 패키지이름과 같을 것입니다.

그리고 4개 permission을 추가해주면 됩니다.

[AndroidManifest.xml]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="당신의 패키지 이름을 적어주세요!">
<!-- Naver Talk 부분 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


그리고 Activity를 하나 생성해야 하므로 activity 또한 추가해줍니다. (저는 안드로이드 스튜디오 내에서 naverTalk라는 패키지를 만들어서 그 안에 NaverTalkActivity 의 이름으로 만들어주었습니다. )

<!-- Naver Talk -->
<activity android:name=".naverTalk.NaverTalkActivity" />


다음 포스팅에서는 본격적으로 소스들을 수정해주는 부분을 살펴보도록 하겠습니다.

반응형

WRITTEN BY
SiriusJ

,
반응형

이번에는 Main화면에서 버튼을 클릭했을 때에 이미지가 다른 이미지로 전환되거나, 나타났다가, 사라졌다가 하는 기능을 구현해보겠습니다.

(* 저의 테스트에서는 대표적으로 해 / 구름 의 이미지를 추가로 첨부하셔야 합니다.)


[MainActivity.class]

public class MainActivity extends Activity{

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        Button sunbtn = (Button)findViewById(R.id.btnSunshine);

        Button cloudbtn = (Button)findViewById(R.id.btnCloudy);

        Button invibtn = (Button)findViewById(R.id.invi);


        View.OnClickListener listener = new View.OnClickListener() {

            ImageView imgsun = (ImageView)findViewById(R.id.imageSun);

            ImageView imgcloud = (ImageView)findViewById(R.id.imageCloud);

            @Override

            public void onClick(View v) {

                if(v.getId() == R.id.btnSunshine) {

 //btnSunshine을 클릭하게 되면, 해당 ImageView의 이미지는 VISIBLE로 set함으로써 보이게 되고, cloud의 이미지는 INVISIBLE로 설정되어 안보이게 됩니다.      

                    imgsun.setVisibility(View.VISIBLE);

                    imgcloud.setVisibility(View.INVISIBLE);

                } else if(v.getId() == R.id.btnCloudy) {

//btnCloudy 버튼을 눌렀을 때에는, 위와 반대가 됩니다. sun이미지는 안보이고, cloud이미지만 보이게 됩니다.

                    imgcloud.setVisibility(View.VISIBLE);

                    imgsun.setVisibility(View.INVISIBLE);

                } else if(v.getId() == R.id.invi) {

//만약 둘다 안보이게 하려면, 둘 다 INVISIBLE로 설정해주면 됩니다.

                    imgcloud.setVisibility(View.INVISIBLE);

                    imgsun.setVisibility(View.INVISIBLE);

                }

            }

        };


        sunbtn.setOnClickListener(listener);           

        cloudbtn.setOnClickListener(listener);

        invibtn.setOnClickListener(listener);

    }

}


///////////////////////////////////////////////////////////////////////////////////////////


[activity_main.xml]
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="horizontal">

<!-- 아래의 id가 btnSunshine, btnCloudy, invi 인 사용자로부터 클릭할 수 있게 하는 총 세 개의 버튼을 만들어 줍니다. -->
    <Button
        android:id="@+id/btnSunshine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Sun"/>

    <Button
        android:id="@+id/btnCloudy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cloud"/>


<!-- 아래의 버튼은 두 이미지 다 안보이도록 하는 버튼입니다. -->
        <Button
            android:id="@+id/invi"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="INVISIBLE"/>
    </LinearLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="3">

<!-- ImageView를 이용하여 이미지 두 개를 전환하거나 보이거나, 안보이도록 해보는 테스트입니다. drawable에 sunshine, cloudy라는 이름으로 이미지파일을 두 개 아무거나 받으셔서 넣어주면 됩니다. -->
        <ImageView
            android:id="@+id/imageSun"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/sunshine"/>
           <!-- android:visibility="invisible"-->

        <ImageView
            android:id="@+id/imageCloud"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/cloudy"
            android:visibility="invisible"/>
    </FrameLayout>

(** 바로 위의 ImageView에서 가장 밑에 줄의 android:visibility="invisible" 을 설정하면, 기본적으로 이미지가 안보이는 상태가 됩니다. 보기와 같이 위의 imageSun 이라는 id 를 가지고 있는 image가 invisible이 주석처리 되어있으므로, 처음 애플리케이션을 실행하면 해당 ImageView의 이미지만 보이고, imageCloud는 숨겨진 상태가 됩니다.)


반응형

WRITTEN BY
SiriusJ

,
반응형

이번에는 애플리케이션을 실행하여 버튼을 눌렀을 때, 메시지 화면으로 이동하고, 메시지를 작성하여 다른 사람에게 보내는 것을 해보도록 하겠습니다.

또한 다른 사람으로부터 문자가 왔을 때, 기존의 문자앱에서 보여지는 것 외에, 애플리케이션에서 또한 해당 문자에 대한 내용을 알려주도록 하는 것을 구성해보도록 하겠습니다.


[AndroidManifest.xml]

user-permission 으로 아래와 같이 추가해주면 됩니다.

<!-- SMS 부분 -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />


그리고 Activity로 SMSActivity, ShowSMSActivity를 아래와 같이 추가해줍니다. ".sms.SMSActivity" 는, 안드로이드 스튜디오에서 sms라는 패키지를 새로 만들어 준 후, 그 안에 SMSActivity를 추가해주었기 때문입니다. 만약 SMSActivity를 MainActivity와 같은 패키지에 만들어 주었다면 ".SMSActivity" 로 해주시면 됩니다.

<activity android:name=".sms.SMSActivity" />
<activity android:name=".sms.ShowSMSActivity" />


또한, Receiver를 등록하여 다른 사람들로부터 SMS가 왔을 때에도 서비스를 해주어야 하므로

다음과 같이 receiver를 등록해줍니다.

<!-- Receiver 부분 -->
<!-- SMS 부분 -->
<receiver android:name=".sms.SMSBroadcast">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>


////////////////////////////////////////////////////////////////////////////////////////////////


[MainActivity.class]

public class MainActivity extends Activity {

private Button smsBtn;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);                

//activity_main 레이아웃에서 버튼을 하나 만들어주면 됩니다! 버튼의 id는 아래와 같이 btn_sms 로 해주시면 됩니다.


smsBtn = (Button)findViewById(R.id.btn_sms);


smsBtn.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

Intent intent = new Intent(MainActivity.this, SMSActivity.class);

startActivity(intent);

}

});

}

}


////////////////////////////////////////////////////////////////////////////////////////////////


[sms 패키지 내에 있는 SMSActivity.class]

public class SMSActivity extends Activity {
//SMS
Context mContext;
EditText smsNumber, smsTextContext;

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

mContext = this;

smsNumber = (EditText)findViewById(R.id.smsNumber);
smsTextContext = (EditText)findViewById(R.id.smsText);
}

//SMS Send 해주는 부분!
public void sendSMS(View v){
String smsNum = smsNumber.getText().toString();
String smsText = smsTextContext.getText().toString();

if (smsNum.length()>0 && smsText.length()>0){
sendSMS(smsNum, smsText);
} else{
Toast.makeText(this, "모두 입력해주세요", Toast.LENGTH_SHORT).show();
}
}

public void sendSMS(String smsNumber, String smsText){
PendingIntent sentIntent = PendingIntent.getBroadcast(this, 0, new Intent("SMS_SENT_ACTION"), 0);
PendingIntent deliveredIntent = PendingIntent.getBroadcast(this, 0, new Intent("SMS_DELIVERED_ACTION"), 0);

registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch(getResultCode()){
case Activity.RESULT_OK:
Toast.makeText(mContext, "전송 완료", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(mContext, "전송 실패", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(mContext, "서비스 지역이 아닙니다", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(mContext, "무선(Radio)가 꺼져있습니다", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(mContext, "PDU Null", Toast.LENGTH_SHORT).show();
break;
}
}
}, new IntentFilter("SMS_SENT_ACTION"));

registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(mContext, "SMS 도착 완료", Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(mContext, "SMS 도착 실패", Toast.LENGTH_SHORT).show();
break;
}
}
}, new IntentFilter("SMS_DELIVERED_ACTION"));

SmsManager mSmsManager = SmsManager.getDefault();
mSmsManager.sendTextMessage(smsNumber, null, smsText, sentIntent, deliveredIntent);
}
}


////////////////////////////////////////////////////////////////////////////////////////////////


[sms패키지 내에 위치한 SMSBroadcast.class]

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class SMSBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context mContext, Intent intent) {
String action = intent.getAction();

if("android.provider.Telephony.SMS_RECEIVED".equals(action)){
Bundle bundle = intent.getExtras();
Object messages[] = (Object[])bundle.get("pdus");
SmsMessage smsMessage[] = new SmsMessage[messages.length];

for(int i = 0; i < messages.length; i++) {
smsMessage[i] = SmsMessage.createFromPdu((byte[]) messages[i]);
}

Date curDate = new Date(smsMessage[0].getTimestampMillis());
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy년 MM월 HH시 mm분 ss초 ", Locale.KOREA);

String originDate = mDateFormat.format(curDate);
String origNumber = smsMessage[0].getOriginatingAddress();
String Message = smsMessage[0].getMessageBody().toString();

Intent showSMSIntent = new Intent(mContext, ShowSMSActivity.class);
showSMSIntent.putExtra("originNum", origNumber);
showSMSIntent.putExtra("smsDate", originDate);
showSMSIntent.putExtra("originText", Message);
showSMSIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

mContext.startActivity(showSMSIntent);
}
}
}


[sms패키지 내에 위치한 ShowSMSActivity.class]

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;


public class ShowSMSActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_sms);

TextView smsDate = (TextView) findViewById(R.id.smsDate);
TextView originNum = (TextView) findViewById(R.id.originNum);
TextView originText = (TextView) findViewById(R.id.originText);

Intent smsIntent = getIntent();

String originNumber = smsIntent.getStringExtra("originNum");
String originDate = smsIntent.getStringExtra("smsDate");
String originSmsText = smsIntent.getStringExtra("originText");

originNum.setText(originNumber);
smsDate.setText(originDate);
originText.setText(originSmsText);
}
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


[activity_show_sms.xml]

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ShowSMSActivity" >

<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="발신자" />

<TextView
android:id="@+id/originNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp" />
</TableRow>

<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="수신 시각" />

<TextView
android:id="@+id/smsDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp" />
</TableRow>

<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="수신 내용" />

<TextView
android:id="@+id/originText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp" />
</TableRow>
</TableLayout>


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


[activity_sms.xml]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="받는사람" />

<EditText
android:id="@+id/smsNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="phone" >
<requestFocus />
</EditText>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="링크를 전송합니다" />

<EditText
android:id="@+id/smsText"
android:layout_width="match_parent"
android:layout_height="200dp"
android:ems="10" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="sendSMS"
android:text="Send" />
</LinearLayout>


반응형

WRITTEN BY
SiriusJ

,