집에 굴러다니는 오래된 모델인 갤럭시윈(그리고, 갤럭시S3, LG 옵티머스 GK)에 Linux Deploy 로 리눅스 설치 한번 해 보려고 루팅을 해 보았습니다.

인터넷에 루팅앱을 검색해 보니 TowelRoot 와 KingoRoot 등이 있더군요~

towelroot.com 에서 받은 앱은 설치까지는 성공했지만 제가 가지고 있는 모델로는 루팅까지는 안되네요~

다음으로 시도해본 kingoapp.com 에서 다운로드 받은 앱으로 시도하였습니다.

KingoRoot

www.kingoapp.com 에서 안드로이드용 KingoRoot.apk 를 다운로드합니다.

 

KingoRoot.apk

다운로드 받은 앱을 실행합니다.

 

설치를 하다보면 Play 프로텍트에 의해 차단됨 메시지 창이 뜨는데 세부정보를 눌러서 계속 설치(안전하지 않음)을 누르면 됩니다.

 

Play 프로텍트에 의해 차단됨

그냥 확인 눌렀다면 다음부터는 더 이상 설치가 되지 않습니다.

다시 설치하려면 애플리케이션 관리에서 "Google Play 스토어" 앱의 데이터를 삭제하고 다시 진행하면 됩니다.

Google Play 스토어 데이터 삭제

앱을 설치하였다면 실행합니다.

 

Kingo ROOT

일부 모델은 위 화면에서 One Clink Root 를 실행하면 안드로이드 앱 만으로도 루팅이 됩니다.

"ROOT FAILED" 가 메시지가 나오면서 실패했다면 아래의 PC 버전으로 루팅하는 방법을 이용합니다.

 

아래는 PC와 연결해서 루팅하는 방법입니다.

 

앱을 실행한 상태에서 이제 윈도우용 Kingo Root 프로그램을 다운로드 받아서 설치합니다.

 

미리 폰에서 USB Debugging 을 허용한 상태여야 합니다.

단말기와 PC 를 USB 케이블로 연결하고 프로그램을 실행합니다.

 

조금 지나면 폰에서 자동으로 Kingo Link 앱을 설치 시도가 됩니다.

세부정보를 눌러서 계속 설치를 합니다.

 

연결이 된 상태입니다.

 

ROOT 를 눌르면 됩니다.

 

몇 분이 지나면 루팅이 완료가 됩니다.

 

PC 에서 위 화면이 뜨고 난 뒤에 폰을 보면 아래와 같은 상태인데 One Clink Root 를 실행하면 됩니다.

 

 

ROOT SUCCEEDED 메시지가 뜨면 루팅이 완료된 상태입니다.

 

루팅이 된 상태에서 PC 의 KingoROOT 프로그램을 다시 실행하면 REMOVE ROOT 와 ROOT AGAIN 메뉴가 나타납니다.

 

그리고 폰에서는 아래와 같은 화면이 보입니다.

루팅이 생각 보다 쉽게 되는군요~

 

블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

URL 로 서버에 있는 파일을 AsyncTask 를 활용하여 비동기식으로 다운로드 하는 예제입니다.

 

DownloaderTask task = new DownloaderTask(url, filename); // 파일의 주소와 저장할 파일경로
task.execute(); // 다운로드 시작

task.cancel(true); // 다운로드 취소

package com.example.asyncdownload;

import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

public class DownloaderTask extends AsyncTask<String, String, Boolean> {
	private String TAG = "DownloaderTask";
	public String fileUrl = null;
	public String filePath = null;
	public long fileSize = -1;
	public long downloadSize = 0;
	public Boolean downloadEnd = false;

	public DownloaderTask(String url, String file) {
		this.fileUrl = url;
		this.filePath = file;
	}

	protected Boolean doInBackground(String... params) {
		Log.i( TAG, "doInBackground" );
		Boolean result = false;
		InputStream input = null;
		OutputStream output = null;
		URLConnection connection = null;

		try {
			URL url = new URL( fileUrl );
			connection = url.openConnection();
			connection.connect();

			fileSize = connection.getContentLength();
			Log.i( TAG, "fileLength : " + fileSize+"");
			input = new BufferedInputStream(url.openStream(), 8192);
			File outputFile = new File( filePath );
			Log.i( TAG, "outputFile : " + outputFile+"");
			output = new FileOutputStream(outputFile);

			byte[] buffer = new byte[8192];
			for (int bytesRead; (bytesRead = input.read(buffer)) >= 0; ) {
				if(isCancelled()) {
					Log.i( TAG, "isCancelled : " + isCancelled()+"");
					break;
				}
				downloadSize += bytesRead;
				publishProgress(downloadSize + "");
				output.write(buffer, 0, bytesRead);
			}
			output.flush();
			output.close();
			input.close();
			if(isCancelled()) {
				if(outputFile.exists()) { // 다운로드 취소된 파일은 삭제
					outputFile.delete();
					Log.i( TAG, "outputFile.exists() : " + outputFile.exists()+"");
				}
				downloadEnd = true;
				result = false;
			} else {
				result = true;
			}
		} catch (IOException e) {
			e.printStackTrace();
			result = false;
		}

		return result;
	}

	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		Log.i( TAG, "onPreExecute" );
	}

	@Override
	protected void onPostExecute(Boolean aBoolean) {
		super.onPostExecute(aBoolean);
		if(fileSize == downloadSize) {
			downloadEnd = true;
		}
		Log.i( TAG, "onPostExecute" );
	}

	@Override
	protected void onProgressUpdate(String... values) {
		super.onProgressUpdate(values);
		long v = Long.parseLong(values[0]);
		//Log.i( TAG, "onProgressUpdate : " + v );
	}
}

  onPreExecute 제일 먼저 호출되는 함수
  doInBackground 실제 다운로드하는 루틴
  onProgressUpdate 다운로드 하면서 publishProgress 함수에 값을 넣으면 실행되는 함수
  onPostExecute 다운로드가 끝나면 호출되는 함수

 

프로그래스바는 호출하는 Activity 에서 구현하면 됩니다.

 

블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

이클립스에서 안드로이드 앱 개발툴을 안드로이드 스튜디오로 바꾸고 나서 에러 잡기가 힘들어 진 것 같네요~

 

Android resource linking failed

error: failed processing manifest.

 

위와 같은 에러로 빌드가 안되는데 인터넷 검색을 해봐도 명확한 답이 없더군요~

 

제 경우엔 카메라 관련해서 file_path.xml 파일을 만들어 둔게 있는데 머지 과정에서 누락된 상태에서 발생한 오류 였습니다.

 

좀 자세하게 해당 부분을 알려주면 좋을텐데 안드로이드 스튜디오에 적응하기 쉽지 않군요~

 

 

블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] Android 8.1 SDK 27 FCM PUSH 알림 문제


안드로이드 8.1 오레오 이상 버전에서 푸쉬는 오는데 알림 소리가 안울리는 문제가 있네요~

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FCMMessageService extends FirebaseMessagingService {
private static final String TAG = "FCMMessageService";
static String registration_id = null;

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getData().size() > 0) {
sendNotification(remoteMessage.getData().get("message"));
}
}

private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);

Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = null;
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = "default_channel_id";
String channelDescription = "Default Channel";
NotificationChannel notificationChannel = notificationManager.getNotificationChannel(channelId);
if (notificationChannel == null) {
int importance = NotificationManager.IMPORTANCE_HIGH;
notificationChannel = new NotificationChannel(channelId, channelDescription, importance);
notificationChannel.setLightColor(Color.GREEN);
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
notificationBuilder = new NotificationCompat.Builder(this, channelId);
} else {
notificationBuilder = new NotificationCompat.Builder(this);
}
notificationBuilder
.setSmallIcon(R.drawable.noti_icon)
.setContentTitle(getString(R.string.app_name))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);

PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
wakelock.acquire(5000);
notificationManager.notify(0, notificationBuilder.build());
}
}

SDK 버전이 올라갈때 마다 가지가지 하네요~ ㅎ


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] FCM PHP 서버 PUSH



서버에서 PHP로 푸쉬메시지를 보내는 코드입니다.


[안드로이드] FCM PHP 서버 PUSH


이전에 사용하던 GCM 서버키를 바꿔주어야 합니다.


function fcm_send($regId, $sendMsg) {

$serverKey = 'AAA...';

$sendMsg = urldecode($sendMsg);

if(is_array($regId)) {

$tokens = $regId;

} else {

$tokens = array();

$tokens[] = $regId;;

}

$message = array( 'message' => $sendMsg );

$fields = array(

'registration_ids' => $tokens,

'data' => $message

);

$headers = array(

'Authorization:key='.$serverKey,

'Content-Type:application/json'

);

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');

curl_setopt($ch, CURLOPT_POST, true);

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));

$result = curl_exec($ch);

if($result === FALSE) {

$result = curl_error($ch);

}

curl_close($ch);

return $result;

}


잘되는군요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] API 23 앱 권한 설정


AndroidManifest.xml 에 있는 퍼미션 관련부분을 아래 코드에 적용하면 됩니다.

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

...

checkGranted();

}


@TargetApi(Build.VERSION_CODES.JELLY_BEAN)

public void checkGranted() {

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.INTERNET) ||

PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) ||

PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) ||

PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) ||

PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.READ_PHONE_STATE) ||

PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.VIBRATE) ||

PackageManager.PERMISSION_GRANTED != checkSelfPermission(Manifest.permission.CAMERA)

) {

requestPermissions(new String[]{

Manifest.permission.INTERNET,

Manifest.permission.ACCESS_NETWORK_STATE,

Manifest.permission.WRITE_EXTERNAL_STORAGE,

Manifest.permission.READ_EXTERNAL_STORAGE,

Manifest.permission.READ_PHONE_STATE,

Manifest.permission.VIBRATE,

Manifest.permission.CAMERA},1);

} else {

}

}

}

@Override

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

if (requestCode == 1) {

if (grantResults.length > 0) {

for (int i=0; i<grantResults.length; ++i) {

if (grantResults[i] == PackageManager.PERMISSION_DENIED) {

new AlertDialog.Builder(this).setTitle("알림").setMessage("권한을 허용하셔야 앱을 이용할 수 있습니다.")

.setPositiveButton("종료", new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

dialog.dismiss();

finish();

}

}).setNegativeButton("권한 설정", new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

dialog.dismiss();

checkGranted();

}

}).setCancelable(false).show();

return;

}

}

}

}

}

API 버전이 올라가니깐 이래저래 참 귀찮게 만드네요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] FileUriExposedException 에러


아래와 같은 에러의 경우가 여러가지 원인이 있겠지만 카메라 촬영 후 앨범에서 여러장 선택해서 전달시 발생한 경우입니다.

E/AndroidRuntime(5472): android.os.FileUriExposedException: file:///storage/0000-0000/DCIM/Camera/20190304_113931_HDR.jpg exposed beyond app through Intent.getData()


이런 경우엔 아래 처럼 onCreate 에 넣어주니 에러가 안나는군요~

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 

StrictMode.setVmPolicy(builder.build());

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

builder.detectFileUriExposure();

}

API 23 부터 너무 짜증이 나네요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] IllegalArgumentException root 에러


API 26 으로 올리고 구글 정책이 얼마나 바뀌었는지 짜증스럽네요~

E/AndroidRuntime(28534): java.lang.IllegalArgumentException: Failed to find configured root that contains


위와 같은 에러시 xml 파일에 아래와 같이 넣어주면 됩니다.


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

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

    <external-path name="storage/emulated/0" path="."/>

    <root-path name="root" path="."/>

</paths>

하나 하나 풀어나가기 힘들군요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] WebView Uncaught TypeError


SDK API 26으로 올렸더니 기존에 잘 동작하던 코드가 제대로 먹히지를 않는군요~

구글이 왜그럴까요~ 점점 짜증나게 만드네요~

버전을 올리면 하위 버전도 호환되게 해야지 제거된 API 들이 은근 많아서 스트레스 받네요~

자바는 이래서 싫어요~

I/chromium(15940): [INFO:CONSOLE(15)] "Uncaught TypeError: window.WebViewCall.setMessage is not a function", source:


위와 같은 메시지가 나오면 아래 처럼 색깔이 들어간 부분을 넣어주면 됩니다.


import android.webkit.JavascriptInterface;

...

mWebView.addJavascriptInterface(new WebViewCall(), "WebViewCall");

...

public class WebViewCall {

@JavascriptInterface

public void setMessage(final String arg, final String arg2) {

...

}

별거 아닐 걸로 환장하는군요~ ㅎ


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[안드로이드] Android Studio gradle 에러


eclipse 에서 안드로이드 스튜디오로 개발툴을 바꾸고 적응하기 힘드네요~

"Could not find com.android.tools.build:gradle:3.3.1." 에러시 File -> Project Structure -> Project 에서 아래 처럼 해주니깐 됩니다.

[안드로이드] Android Studio gradle 에러

이런 오류는 구글링도 이제 힘드네요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,