Android 통신 - Sizuha/devdog GitHub Wiki
네트워크가 사용 가능한지 확인
// ネットワークの接続を確認
public static boolean networkCheck(Context context){
final ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) return false;
final NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null ) {
return info.isConnected();
}
else {
return false;
}
}
전화번호 가져오기
// <uses-permission android:name="android.permission.READ_PHONE_STATE" />
TelephonyManager tMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String mPhoneNumber = tMgr.getLine1Number();
HTTP
네트워크 통신을 메인 스레드에서 처리하면 런타임에 android.os.NetworkOnMainThreadException 예외가 발생한다. 네트워크 통신은 반드시 AsyncTask 등을 이용해서 비동기로 처리해야 한다.
Apache HTTP Client
Android 6에서 Apache HTTP Client 라이브러리가 제거되었다. 대신 [https://developer.android.com/reference/java/net/HttpURLConnection.html| HttpURLConnection] 을 권장하고 있다.
그래도 계속 사용하고 싶다면, App/build.gradle 파일의 첫 부분을 다음과 같이 수정한다.
apply plugin: 'com.android.application'
android {
useLibrary 'org.apache.http.legacy'
...
HttpURLConnection
public class NetUtil {
public interface IOnHttpTaskEvent {
void onResponse(Response response);
}
public static class Response {
public boolean succeed;
public String error;
public String content;
private JSONObject json = null;
public JSONObject getJSONObject() {
if (json != null) return json;
if (content != null) {
try {
json = new JSONObject(content);
return json;
}
catch (JSONException e) {
error = e.toString();
succeed = false;
}
}
return json = new JSONObject();
}
}
public static Response http_get(String url, Map<String,String> params) {
return http_request(url, params, RequestMethod.GET);
}
public static Response http_post(String url, Map<String,String> params) {
return http_request(url, params, RequestMethod.POST);
}
public static Response http_post(String url, String post_params) {
return http_request_raw(url, post_params, RequestMethod.POST);
}
public static Response http_post(String url, JSONObject json) {
return http_request_raw(url, json.toString(), RequestMethod.POST);
}
public enum RequestMethod {
GET(0),
POST(1),
DELETE(2);
int method;
RequestMethod(int method_code) {
method = method_code;
}
public String toString() {
switch (method) {
case 1: return "POST";
case 2: return "DELETE";
default: return "GET";
}
}
public boolean is_post() {
return method == 1;
}
}
public static String mapToString(Map<String,String> params) {
if (params == null) return null;
String param_data = "";
boolean first = true;
for (Map.Entry<String,String> kv: params.entrySet()) {
try {
param_data += (first ? "" : "&") +
URLEncoder.encode(kv.getKey(), "UTF-8") + "=" + URLEncoder.encode(kv.getValue(), "UTF-8");
first = false;
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return param_data;
}
public static Response http_request(String url, Map<String,String> params, RequestMethod request_method) {
return http_request_raw(url, mapToString(params), request_method);
}
protected static Response http_request_raw(String url, String param_str, RequestMethod request_method) {
final Response response = new Response();
HttpURLConnection urlConn = null;
try {
URL _url;
if (request_method.is_post()) {
_url = new URL(url);
}
else if (param_str != null && param_str.length() > 0) {
_url = new URL(url + "?" + param_str);
}
else {
_url = new URL(url);
}
// for DEBUG
Logger.d("http_request_raw[URL]: " + _url.toString());
urlConn = (HttpURLConnection) _url.openConnection();
urlConn.setReadTimeout(60000);
urlConn.setConnectTimeout(60000);
urlConn.setDoInput(true);
urlConn.setDoOutput(request_method.is_post());
urlConn.setRequestMethod(request_method.toString());
if (param_str != null && param_str.length() > 0 && request_method.is_post()) {
final OutputStream os = urlConn.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write(param_str);
writer.flush();
writer.close();
os.close();
}
urlConn.connect();
// HTTPレスポンスコード
final int status = urlConn.getResponseCode();
response.succeed = status == HttpURLConnection.HTTP_OK;
if (response.succeed) {
// 取得したテキストを格納する変数
final StringBuilder result = new StringBuilder();
// 通信に成功した
// テキストを取得する
final InputStream in = urlConn.getInputStream();
String encoding = urlConn.getContentEncoding();
Logger.d("encoding: " + encoding);
if (encoding == null || encoding.length() < 1) {
encoding = "UTF-8";
}
final InputStreamReader inReader = new InputStreamReader(in, encoding);
final BufferedReader bufReader = new BufferedReader(inReader);
String line;
// 1行ずつテキストを読み込む
while ((line = bufReader.readLine()) != null) {
result.append(line);
}
bufReader.close();
inReader.close();
in.close();
response.content = result.toString();
// for DEBUG
Logger.d("http_request_raw[response.content]: " + response.content);
}
else {
response.error = String.valueOf(status);
// for DEBUG
Logger.d("http_request_raw[response.error]: " + response.error);
}
}
catch (MalformedURLException e) {
e.printStackTrace();
response.succeed = false;
response.error = e.toString();
}
catch (IOException e) {
e.printStackTrace();
response.succeed = false;
response.error = e.toString();
}
finally {
if (urlConn != null) urlConn.disconnect();
}
return response;
}
public static class HttpAsyncTask extends AsyncTask<String, Void, Response> {
private String request_params;
private IOnHttpTaskEvent eventRecv;
private RequestMethod method = RequestMethod.GET;
public HttpAsyncTask setMethod(RequestMethod request_method) {
method = request_method;
return this;
}
public HttpAsyncTask setParams(Map<String,String> params) {
request_params = mapToString(params);
return this;
}
public HttpAsyncTask setParams(JSONObject params) {
request_params = params.toString();
method = RequestMethod.POST;
return this;
}
public HttpAsyncTask setListener(IOnHttpTaskEvent listener) {
eventRecv = listener;
return this;
}
@Override
protected Response doInBackground(String... params) {
String url = null;
for (String p: params) {
url = p;
break;
}
Logger.d("request params: " + request_params);
return http_request_raw(url, request_params, method);
}
@Override
protected void onPostExecute(Response response) {
if (eventRecv != null)
eventRecv.onResponse(response);
}
}
}
파일 내려받기
public class FileDownloader extends AsyncTask<String, String, Integer> {
final static int BUFFER_SIZE = 4096;
private String storagePath = "";
public void setStagePath(String path) {
storagePath = path;
}
public static interface IOnDownloadEvent {
void onOneFileDownloadEnd(String filenameWithPath);
void onDownloadTotalEnd(int download_count);
}
public IOnDownloadEvent downloadEventRecv;
public boolean overwrite = false;
@Override
protected Integer doInBackground(String... urls) {
int dn_cnt = 0;
for (String url_str : urls) {
// Escape early if cancel() is called
if (isCancelled()) break;
File outFile = null;
try {
URL url = new URL(url_str);
final String out_filename = URLUtil.guessFileName(url_str, null, null);
final String out_filenameWithPath = Environment.getExternalStorageDirectory().toString() +
"/" + storagePath + "/" + out_filename;
outFile = new File(out_filenameWithPath);
if (!overwrite &&outFile.exists()) continue;
URLConnection connection = url.openConnection();
connection.connect();
outFile.mkdirs();
InputStream input = new BufferedInputStream(url.openStream(), BUFFER_SIZE);
OutputStream output = new FileOutputStream(outFile);
byte data[] = new byte[BUFFER_SIZE];
int read_count;
while ((read_count = input.read(data)) != -1) {
output.write(data, 0, read_count);
dn_cnt++;
}
output.flush();
output.close();
input.close();
if (downloadEventRecv != null) downloadEventRecv.onOneFileDownloadEnd(out_filenameWithPath);
}
catch (MalformedURLException e) {
e.printStackTrace();
continue;
}
catch (IOException e) {
e.printStackTrace();
if (outFile != null) outFile.delete();
continue;
}
}
return dn_cnt;
}
@Override
protected void onPostExecute(Integer dnCnt) {
if (downloadEventRecv != null) downloadEventRecv.onDownloadTotalEnd(dnCnt);
super.onPostExecute(dnCnt);
}
}
다운 받기 전에 파일 크기 알아내기
URL url = new URL("http://server.com/file.mp3");
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
int file_size = urlConnection.getContentLength();
multipart/form-data
http://qiita.com/informationsea/items/778d9525c3aaded73577
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.util.Map;
import java.util.UUID;
/**
* Copyright (C) 2014 Yasunobu OKAMURA
* MIT License
*/
public class HttpMultipartSender {
private HttpMultipartSender(){} // cannot make instance
// this function is implemented based on http://www.androidsnippets.com/multipart-http-requests
public static void sendMultipart(HttpURLConnection connection, String filefield, File filepath, Map<String, String> textdata) throws IOException {
final String twoHyphens = "--";
final String boundary = "*****"+ UUID.randomUUID().toString()+"*****";
final String lineEnd = "\r\n";
final int maxBufferSize = 1024*1024*3;
DataOutputStream outputStream;
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+boundary);
outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"" + filefield + "\"; filename=\"" + filepath.getName() +"\"" + lineEnd);
outputStream.writeBytes("Content-Type: application/octet-stream" + lineEnd);
outputStream.writeBytes("Content-Transfer-Encoding: binary" + lineEnd);
outputStream.writeBytes(lineEnd);
FileInputStream fileInputStream = new FileInputStream(filepath);
int bytesAvailable = fileInputStream.available();
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while(bytesRead > 0) {
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
for (Map.Entry<String, String> entry : textdata.entrySet()) {
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + lineEnd);
outputStream.writeBytes("Content-Type: text/plain"+lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(entry.getValue());
outputStream.writeBytes(lineEnd);
}
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
outputStream.close();
}
}
SMS
필요한 퍼미션
<uses-permission android:name="android.permission.SEND_SMS" />
SmsManager API
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage("phoneNo", null, "sms message", null, null);
Built-in SMS application
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.putExtra("sms_body", "--- SMS 내용 ---");
sendIntent.setType("vnd.android-dir/mms-sms");
startActivity(sendIntent);
protected void sendEmail() {
Log.i("Send email", "");
String[] TO = {""};
String[] CC = {""};
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setData(Uri.parse("mailto:"));
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, TO);
emailIntent.putExtra(Intent.EXTRA_CC, CC);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Your subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message goes here");
try {
startActivity(Intent.createChooser(emailIntent, "Send mail..."));
finish();
Log.i("Finished sending email...", "");
}
catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(MainActivity.this, "There is no email client installed.", Toast.LENGTH_SHORT).show();
}
}
URL Scheme
일단은 다음과 같은 intent 스킴을 이용하는 방법을 권장하고 있다.
intent:
HOST/URI-path // Optional host
#Intent;
package=[string];
action=[string];
category=[string];
component=[string];
scheme=[string];
end;
Example:
<a href="intent://scan/#Intent;scheme=zxing;package=com.google.zxing.client.android;S.browser_fallback_url=http%3A%2F%2Fzxing.org;end"> Take a QR code </a>
간단히 iOS처럼 App Scheme 이름을 그대로 활용할 수도 있다.
public static void openIntentByUrl(Context c, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(url)); // ex) "bill2://test2?r=received"
c.startActivity(intent);
}