출처:https://dlucky.tistory.com/m/187



클릭 이벤트를 강제로 발생시키려면 다음과 같이 하면 됩니다.

Button tempB = ..........

tempB.performClick();  // 클릭 이벤트
tempB.performLongClick(); // 롱 클릭 이벤트

https://stackoverflow.com/questions/36184641/kotlin-iterate-through-a-jsonarray/36188796


Realm class:

import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.Required

open class Person(

        @PrimaryKey open var id: Long = 0,

        @Required
        open var name: String = ""

) : RealmObject() {

}

The JSONArray:

{
    "persons":[
        {
           "id":0,
           "name":"Biatrix"
        },
        {
           "id":1,
           "name":"Bill"
        },
        {
           "id":2,
           "name":"Oren"
        },
        {
           "id":3,
           "name":"Budd"
        }
    ]
}

아래 코드를 이용하여 JSON array 내부 오브젝트 사용
for (i in 0..(persons.length() - 1)) {
    val item = persons.getJSONObject(i)

    // Your code here
} 


출처:https://kamang-it.tistory.com/entry/VolleyJavavolley%EB%A1%9C-json%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B0%9B%EA%B8%B03

 

 

참고:

[Volley][Java]Android Volley 기본과 get으로 주고받기(1)

[Volley][Java]volley로 post로 주고받기(2)

 

volley로 json데이터를 주고받아보도록하자.

설정의 설명은 생략할테니 참고부분을 참고하라.

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.theceres.myapplication">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

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

manifest설정이다.

 

액티비티의 모습이다.

 

서버에서 제공하는 해당 url은 위와 같다.

그럼 해당 json데이터를 받아보도록 하자.

 

package net.theceres.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MAIN";
private TextView tv;
private RequestQueue queue;

private String id;
private String pw;
private JSONArray language;
private JSONObject item;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tvMain);

queue = Volley.newRequestQueue(this);
String url = "http://192.168.0.9:5000/";

final JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
id = response.getString("id");
pw = response.getString("pw");
language = response.getJSONArray("language");
item = response.getJSONObject("item");
tv.setText(id + ":" + pw + ":" + language + ":" + item);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {

}
});

jsonRequest.setTag(TAG);
queue.add(jsonRequest);
}

@Override
protected void onStop() {
super.onStop();
if (queue != null) {
queue.cancelAll(TAG);
}
}
}

url은 여러분의 url로 해라.

위와 같이 사용하면 json데이터를 받을 수있다.

여기서 우리는 StringRequest가 아니라 JsonObjectRequest라는 조금 다른 request를 사용하였다.

받는 변수의 타입은 해당 타입과 맞추어준다.

위의 예제에서 json object와 json array를 받는 예제를 볼 수 있다.

 

보다시피 해당 값을 받을 수 있다.

 

하지만 해당 솔루션은 문제가 있다.

바로 넘어오는 타입이 Json Array인지, Json Object인지, null인지 알수 없다는 것이다.

즉 보내는 쪽에서 보내는 타입을 신경써야 한다는 소리이다.

사실 이게 크게 문제는 안 될수 있지만 사용하기 조금 껄끄럽다.

이 문제점을 해결하고 싶다면 구글에서 제공하는 gson을 사용하는게 좋다.

gson을 사용하는 예제를 보도록하자.

 

gson은 mvn레포지터리에 존재한다.

 

해당 의존성을 복사해서 넣어준다.

 

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

// https://mvnrepository.com/artifact/com.android.volley/volley
compile group: 'com.android.volley', name: 'volley', version: '1.0.0'
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
}

이렇게 넣어주면 된다.

 

package net.theceres.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MAIN";
private TextView tv;
private RequestQueue queue;

private String id;
private String pw;
private JSONArray language;
private JSONObject item;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tvMain);

queue = Volley.newRequestQueue(this);
String url = "http://192.168.0.9:5000/";

StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(response);
tv.setText(jsonElement + "\n");
tv.setText(tv.getText() + jsonElement.getClass().getName() + "\n");
tv.setText(tv.getText() + ((JsonObject) jsonElement).get("language").getClass().getName() + "\n");
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {

}
});

stringRequest.setTag(TAG);
queue.add(stringRequest);
}

@Override
protected void onStop() {
super.onStop();
if (queue != null) {
queue.cancelAll(TAG);
}
}
}

 

여기서는 json request가 아닌 string request를 사용한다.

row하게 문자열로 받아서 json parser로 json화 시킨다.

gson은 json의 개념을 추상화한 json element가 존재한다.

그리고 jsonElement의 타입을 확인해서 Array면 JsonArray로 사용하고 Object면 JsonObject로 사용한다.

또한 get으로 자식 엘레멘트를 가져올 수 있다.

 

결과를 확인해보자.

gson이 훨씬 유동적이게 사용할 수 있음을 확인할 수 있다.

 

 

 



[안드로이드] extends Fragment 구현시 contexet 구하는 방법




Fragment는 Activity가 아니라서 MainActivity.this, 또는 this 사용이 안됩니다.



그럴 때는 getActivity().getApplicationContext() 를 사용합니다!!




또는


Context ct;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.fragment_01, container, false);

ct = container.getContext();
}



아래 방법이 더 정확한 방법인 것 같다.



출처: https://es1015.tistory.com/124 [개발 / 폰꾸미기]

출처: https://altongmon.tistory.com/694 [IOS를 Java]

 

이번 포스팅에서는 WifiManager 클래스를 사용해서 주변 ap(Access Point) wifi목록을

스캔하는 예제입니다.

실행 결과 먼저 보여드립니다.

아래 정보들 말고도 더 확인할 수 있는데, 저는 이렇게만 만들었습니다.

 

먼저

Manifest.xml에 아래 퍼미션들을 추가해줍니다.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-feature android:name="android.hardware.wifi"/>

 

그리고 저는 데이터 바인딩을 사용하기 때문에

build.gradle(Module:app) 을 열어

android{} 중괄호 블록 내부에

dataBinding {
enabled true
}

데이터 바인딩을 허용하는 코드를 넣어줍니다.

 

그리고 레이아웃에서 저는 CardView 와 RecyclerView를 둘 다 사용했는데요.

그래서 

dependencies {

}

블록에 아래 3가지를 implementation해줍니다.

implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'

 

데이터를 담을 AccessPoint 클래스와 RecyclerView에 데이터를 넣어주고 처리하기 위한

RecyclerViewAdapter 클래스를 상속 받는 AccessPointAdapter 도 만드러 줍니다.

 

AccessPoint.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

public class AccessPoint {

 

    private String ssid;

    private String bssid;

    private String rssi;

 

    public AccessPoint(String ssid, String bssid, String rssi) {

        this.ssid = ssid;

        this.bssid = bssid;

        this.rssi = rssi;

    }

 

    public String getSsid() {

        return ssid;

    }

 

    public String getBssid() {

        return bssid;

    }

 

    public String getRssi() {

        return rssi;

    }

}

 

Colored by Color Scripter

cs

 

AccessPointAdapter.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

public class AccessPointAdapter extends RecyclerView.Adapter {

 

    private Vector<AccessPoint> accessPoints;

    private Context context;

 

    AccessPointAdapter(Vector<AccessPoint> accessPoints, Context context) {

        this.accessPoints = accessPoints;

        this.context = context;

    }

 

    @NonNull

    @Override

    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        RecyclerView.ViewHolder holder;

        ItemAccesspointBinding binding = ItemAccesspointBinding.inflate(LayoutInflater.from(context), parent, false);

        holder = new AccessPointHolder(binding);

        return holder;

    }

 

    @Override

    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

        AccessPointHolder accessPointHolder = (AccessPointHolder)holder;

        final ItemAccesspointBinding binding = accessPointHolder.binding;

        binding.cardView.setRadius(20.0f);

        String ssid = "SSID : " + accessPoints.get(position).getSsid();

        String bSsid = "BSSID : " + accessPoints.get(position).getBssid();

        String rssi = "RSSI : " + accessPoints.get(position).getRssi();

        binding.ssidTextView.setText(ssid);

        binding.bssidTextView.setText(bSsid);

        binding.rssiLevelTextView.setText(rssi);

 

    }

 

    @Override

    public int getItemCount() {

        return accessPoints.size();

    }

 

    private class AccessPointHolder extends RecyclerView.ViewHolder {

        ItemAccesspointBinding binding;

 

        AccessPointHolder(ItemAccesspointBinding binding) {

            super(binding.getRoot());

            this.binding = binding;

        }

    }

 

}

 

Colored by Color Scripter

cs

 

---------------------------------------------------------------------------------------------------------

 

---------------------------------------------------------------------------------------------------------

 

 

 

 

 

이제 xml 차례입니다.

 

recyclerView의 아이템으로 들어갈 layout

item_accesspoint.xml

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

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

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

    xmlns:app="http://schemas.android.com/apk/res-auto">

 

    <android.support.v7.widget.CardView

        android:layout_margin="10dp"

        android:id="@+id/cardView"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

 

        <android.support.constraint.ConstraintLayout

            android:padding="10dp"

            android:background="@color/colorAccent"

            android:id="@+id/cardLayout"

            android:layout_width="match_parent"

            android:layout_height="wrap_content">

            <TextView

                app:layout_constraintTop_toTopOf="@+id/cardLayout"

                app:layout_constraintStart_toStartOf="@+id/cardLayout"

                app:layout_constraintBottom_toTopOf="@+id/bssidTextView"

                android:id="@+id/ssidTextView"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:textSize="@dimen/textSize"/>

            <TextView

                app:layout_constraintStart_toStartOf="@+id/ssidTextView"

                app:layout_constraintTop_toBottomOf="@+id/ssidTextView"

                app:layout_constraintBottom_toTopOf="@+id/rssiLevelTextView"

                android:id="@+id/bssidTextView"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:textSize="@dimen/textSize" />

            <TextView

                app:layout_constraintStart_toStartOf="@+id/ssidTextView"

                app:layout_constraintTop_toBottomOf="@+id/bssidTextView"

                app:layout_constraintBottom_toBottomOf="@+id/cardLayout"

                android:id="@+id/rssiLevelTextView"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:textSize="@dimen/textSize" />

        </android.support.constraint.ConstraintLayout>

    </android.support.v7.widget.CardView>

 

</layout>

Colored by Color Scripter

cs

 

여기서 사용된 @dimen/textSize 는 20sp 입니다.

 

activity_main.xml

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

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

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

    xmlns:app="http://schemas.android.com/apk/res-auto"

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

 

    <android.support.constraint.ConstraintLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        tools:context="wifi.rowan.com.wifilistscanner.MainActivity">

        <android.support.v7.widget.Toolbar

            android:background="@color/colorPrimary"

            android:id="@+id/toolbar"

            app:layout_constraintTop_toTopOf="parent"

            app:layout_constraintBottom_toTopOf="@+id/accessPointRecyclerView"

            android:layout_width="match_parent"

            android:layout_height="wrap_content">

            <TextView

                android:textColor="#FFFFFFFF"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:layout_gravity="center"

                android:text="Wifi List"/>

        </android.support.v7.widget.Toolbar>

        <android.support.v7.widget.RecyclerView

            app:layout_constraintTop_toBottomOf="@+id/toolbar"

            app:layout_constraintBottom_toBottomOf="parent"

            android:id="@+id/accessPointRecyclerView"

            android:layout_width="match_parent"

            android:layout_height="0dp"/>

    </android.support.constraint.ConstraintLayout>

</layout>

Colored by Color Scripter

cs

 

마지막으로

MainActivity.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

public class MainActivity extends AppCompatActivity {

 

    Vector<AccessPoint> accessPoints;

    LinearLayoutManager linearLayoutManager;

    AccessPointAdapter accessPointAdapter;

    WifiManager wifiManager;

    List<ScanResult> scanResult;

    ActivityMainBinding binding;

    /* Location permission 을 위한 필드 */

    public static final int MULTIPLE_PERMISSIONS = 10// code you want.

    // 원하는 권한을 배열로 넣어줍니다.

    String[] permissions = new String[]{

            Manifest.permission.ACCESS_COARSE_LOCATION

    };

    /* Location permission 을 위한 필드 */

 

    @Override

    protected void onStart() {

        super.onStart();

        if (Build.VERSION.SDK_INT >= 23) {

            if (!checkPermissions()) {

                finish();

            }

        }

    }

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

        linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

        binding.accessPointRecyclerView.setLayoutManager(linearLayoutManager);

        accessPoints = new Vector<>();

        if (wifiManager != null) {

            if (!wifiManager.isWifiEnabled()) {

                wifiManager.setWifiEnabled(true);

            }

            final IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

            filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);

            registerReceiver(mWifiScanReceiver, filter);

            wifiManager.startScan();

        }

    }

 

 

    private BroadcastReceiver mWifiScanReceiver = new BroadcastReceiver() {

 

        @Override

        public void onReceive(Context context, Intent intent) {

            final String action = intent.getAction();

            if (action != null) {

                if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {

                    getWIFIScanResult();

                    wifiManager.startScan();

                } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {

                    context.sendBroadcast(new Intent("wifi.ON_NETWORK_STATE_CHANGED"));

                }

 

            }

 

        }

    };

 

    public void getWIFIScanResult() {

        scanResult = wifiManager.getScanResults();

        if (accessPoints.size() != 0) {

            accessPoints.clear();

        }

        for (int i = 0; i < scanResult.size(); i++) {

            ScanResult result = scanResult.get(i);

            if (result.frequency < 3000) {

                Log.d(". SSID : " + result.SSID,

                        result.level + ", " + result.BSSID);

                accessPoints.add(new AccessPoint(result.SSID, result.BSSID, String.valueOf(result.level)));

            }

        }

        accessPointAdapter = new AccessPointAdapter(accessPoints, MainActivity.this);

        binding.accessPointRecyclerView.setAdapter(accessPointAdapter);

        accessPointAdapter.notifyDataSetChanged();

    }

 

    @Override

    protected void onDestroy() {

        super.onDestroy();

        unregisterReceiver(mWifiScanReceiver);

    }

 

    /* Location permission 을 위한 메서드들 */

    private boolean checkPermissions() {

        int result;

        List<String> listPermissionsNeeded = new ArrayList<>();

        for (String p : permissions) {

            result = ContextCompat.checkSelfPermission(MainActivity.this, p);

            if (result != PackageManager.PERMISSION_GRANTED) {

                listPermissionsNeeded.add(p);

            }

        }

        if (!listPermissionsNeeded.isEmpty()) {

            ActivityCompat.requestPermissions(MainActivity.this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), MULTIPLE_PERMISSIONS);

            return false;

        }

        return true;

    }

 

    @Override

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

        switch (requestCode) {

            case MULTIPLE_PERMISSIONS: {

                if (grantResults.length > && grantResults[0== PackageManager.PERMISSION_GRANTED) {

                    Log.d("permission""granted");

                }

            }

        }

    }

/* Location permission 을 위한 메서드들 */

}

 

Colored by Color Scripter

cs

 

코드를 보고 순서대로 따라하시면 큰 어려움 없이 하실 수 있을 거에요^^

이상입니다.

감사합니다.



출처: https://altongmon.tistory.com/694 [IOS를 Java]

출처: https://android--code.blogspot.com/2018/03/android-kotlin-webview-example.html


MainActivity.kt

package com.cfsuman.kotlinexamples

import android.content.Context
import android.graphics.Bitmap
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebChromeClient
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import android.os.Build
import android.support.v7.app.AlertDialog
import android.view.View


class MainActivity : AppCompatActivity() {
    private val url = "https://developer.android.com/index.html"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Get the web view settings instance
        val settings = web_view.settings

        // Enable java script in web view
        settings.javaScriptEnabled = true

        // Enable and setup web view cache
        settings.setAppCacheEnabled(true)
        settings.cacheMode = WebSettings.LOAD_DEFAULT
        settings.setAppCachePath(cacheDir.path)


        // Enable zooming in web view
        settings.setSupportZoom(true)
        settings.builtInZoomControls = true
        settings.displayZoomControls = true


        // Zoom web view text
        settings.textZoom = 125


        // Enable disable images in web view
        settings.blockNetworkImage = false
        // Whether the WebView should load image resources
        settings.loadsImagesAutomatically = true
        
        
        // More web view settings
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            settings.safeBrowsingEnabled = true  // api 26
        }
        //settings.pluginState = WebSettings.PluginState.ON
        settings.useWideViewPort = true
        settings.loadWithOverviewMode = true
        settings.javaScriptCanOpenWindowsAutomatically = true
        settings.mediaPlaybackRequiresUserGesture = false


        // More optional settings, you can enable it by yourself
        settings.domStorageEnabled = true
        settings.setSupportMultipleWindows(true)
        settings.loadWithOverviewMode = true
        settings.allowContentAccess = true
        settings.setGeolocationEnabled(true)
        settings.allowUniversalAccessFromFileURLs = true
        settings.allowFileAccess = true

        // WebView settings
        web_view.fitsSystemWindows = true


        /*
            if SDK version is greater of 19 then activate hardware acceleration
            otherwise activate software acceleration
        */
        web_view.setLayerType(View.LAYER_TYPE_HARDWARE, null)


        // Set web view client
        web_view.webViewClient = object: WebViewClient(){
            override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
                // Page loading started
                // Do something
                toast("Page loading.")

                // Enable disable back forward button
                button_back.isEnabled = web_view.canGoBack()
                button_forward.isEnabled = web_view.canGoForward()
            }

            override fun onPageFinished(view: WebView, url: String) {
                // Page loading finished
                // Display the loaded page title in a toast message
                toast("Page loaded: ${view.title}")

                // Enable disable back forward button
                button_back.isEnabled = web_view.canGoBack()
                button_forward.isEnabled = web_view.canGoForward()
            }
        }


        // Set web view chrome client
        web_view.webChromeClient = object: WebChromeClient(){
            override fun onProgressChanged(view: WebView, newProgress: Int) {
                progress_bar.progress = newProgress
            }
        }


        // Load button click listener
        button_load.setOnClickListener{
            // Load url in a web view
            web_view.loadUrl(url)
        }


        // Back button click listener
        button_back.setOnClickListener{
            if(web_view.canGoBack()){
                // Go to back history
                web_view.goBack()
            }
        }


        // Forward button click listener
        button_forward.setOnClickListener{
            if(web_view.canGoForward()){
                // Go to forward history
                web_view.goForward()
            }
        }
    }



    // Method to show app exit dialog
    private fun showAppExitDialog() {
        val builder = AlertDialog.Builder(this)

        builder.setTitle("Please confirm")
        builder.setMessage("No back history found, want to exit the app?")
        builder.setCancelable(true)

        builder.setPositiveButton("Yes", { _, _ ->
            // Do something when user want to exit the app
            // Let allow the system to handle the event, such as exit the app
            super@MainActivity.onBackPressed()
        })

        builder.setNegativeButton("No", { _, _ ->
            // Do something when want to stay in the app
            toast("thank you.")
        })

        // Create the alert dialog using alert dialog builder
        val dialog = builder.create()

        // Finally, display the dialog when user press back button
        dialog.show()
    }



    // Handle back button press in web view
    override fun onBackPressed() {
        if (web_view.canGoBack()) {
            // If web view have back history, then go to the web view back history
            web_view.goBack()
            toast("Going to back history")
        } else {
            // Ask the user to exit the app or stay in here
            showAppExitDialog()
        }
    }
}


// Extension function to show toast message
fun Context.toast(message: String) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#edfaed"
    android:padding="0dp"
    android:orientation="vertical"
    >
    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <Button
            android:id="@+id/button_load"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Load URL"
            android:textAllCaps="false"
            />
        <Button
            android:id="@+id/button_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Back"
            android:textAllCaps="false"
            android:enabled="false"
            />
        <Button
            android:id="@+id/button_forward"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Forward"
            android:textAllCaps="false"
            android:enabled="false"
            />
    </LinearLayout>
    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />
</LinearLayout>

  

출처: https://liveonthekeyboard.tistory.com/entry/안드로이드-스튜디오-GitHub-연동과-add-commit-push-개념 [키위남]


개발자라면 거역할 수 없는 운명


GitHub 


자신의 소스코드를 관리하는 측면의 장점도 있지만


전세계의 수많은 개발자들이 올리는 검증된 오픈 소스들을 브라우징 할 수 있는 좋은 툴입니다.




안드로이드 스튜디오에서 GitHub 와 연동하는 방법을 설명해드리겠습니다.




그 전에 짧게 깃에 대해 설명드립니다.




0. Git 이란?










개략적인 깃의 동작입니다.


Working Directory 에서 깃으로 관리 안되고 있는 파일들을 관리를 시작하려 합니다.


관리 하려는 목록에 추가(Add) 하고,


이 관리할 파일들이 확정 (Commit) 되면 로컬 저장소(Head)에 저장이 되고


이 로컬 저장소에 있는 파일을 원격 서버인 (Github) 에 발행(Push) 합니다.


아직 정확히 이해 못하셔도 괜찮습니다. 일단 이런 프로세스를 가진 형상관리 프로그램이라는 것만 감 잡으시면 됩니다!.





안드로이드 - GitHub 연동하기.


1. Git 다운로드


https://git-scm.com/downloads  (Git 다운로드 url)






링크를 통해 접속하게 되면 위와 같은 화면이 나옵니다.


여기서 여러분이 사용하는 OS 에 맞춰 Git를 설치해주세요.


설치에는 특별한 사항은 없고 NEXT만 눌러주시면 됩니다. (OS X는 Xcode 설치시 git이 자동으로 설치됩니다.) 


설치가 정상적으로 완료되면 CMD 창 (OS X는 터미널) 에서 git 이라는 명령어에 아래와 같은 출력이 나오면 정상적으로 설치 된 것입니다.








2.  GitHub 계정 생성



https://github.com/join?source=header-home   (깃 허브 계정 생성 url) 




 링크로 이동하시면 위와 같은 회원가입 양식이 나옵니다.


 모두 작성하고 회원 가입을 완료까지만 하시면 됩니다.


 안드로이드 스튜디오 내부 기능으로 GitHub와 연동을 하게 되면 자동으로 레포지터리가 생성되기 때문에 굳이 Github 홈페이지에서 따로 생성 안하셔도 됩니다!







3. 안드로이드 스튜디오 설정



먼저 깃허브와 연동할 프로젝트를 열어줍니다.


그리고 메뉴 중 VCS ] >> [ Import into Version Control ] >> [ Create Git Repository ]  를 선택해 줍니다. 





그러면 아래와 같은 화면이 나옵니다.


자신의 프로젝트가 있는 폴더를 선택해 줍니다. ( AndroidStudioProjects > "ProjectName" ) 








그 다음 새로운 VCS Root 를 생성할거냐는 질문에 당연히 Yes를 눌러주세요.







방금 작업이 끝난 후에 안드로이드 프로젝트에 있는 파일 이름들이 전부다 빨강색 으로 변한 것을 알 수 있습니다.




이유는 아직 로컬 깃 저장소 (방금 지정한 깃 저장소) 에 저 파일들이 Add 되어 있지 않기 때문입니다.


아직 깃으로 형상관리를 시작하지 않았다. "파일 변경 사항을 추적 하지 않는 중이다~~~" 라고 알려주는 것입니다.


물론 Add와 Commit 하게 되면 색은 다시 돌아옵니다.




여기까지는 자신의 컴퓨터 (로컬 저장소) 에 Git 를 설정하였고


이제는 아까 회원가입한 GitHub 에 자신의 소스를 올려보도록 하겠습니다.






4. 안드로이드 스튜디오 - GitHub 연동하기




 안드로이드 스튜디오 설정으로 들어갑니다. (OS X 는 Preferences 입니다. Window는 안본지 오래되서..아마 Setting..?)






설정에서 [ Version Control ] >> [ GitHub ] 로 이동하면 





GitHub 의 아이디와 비밀번호를 요구합니다. 


아까 가입한 정보를 입력하고 Test 버튼을 누르시면 됩니다.



Test Button Click!

 





테스트 성공한 다음 OK 눌러서 빠져나가게 되면








이렇게 이 GitHub 레포지터리의 마스터 (관리자) 비밀번호를 설정하라 합니다.


이 프로젝트가 다른 개발자와 협업을 해야하는 경우 개인적인 비밀번호가 아닌 회사 혹은 프로젝트 비밀번호를 설정해주시면 됩니다.



마스터 비밀번호까지 설정하고 난 뒤,



왼쪽 사이드바 상단 Android를 Project 로 바꿔주세요.


바꾼 뒤 프로젝트 전체 파일을 우클릭 >> Git >> Add







프로젝트의 모든 파일을 Add 하게 되면 Stage area (준비 영역) 으로 이동됩니다.



아직 로컬 저장소에 저장 되진 않았지만 Commit 할 때 로컬 저장소에 저장될 것들 인거죠.


Add 하게 되면 빨강색이였던 이름들이 초록색으로 바뀝니다.















그 다음 메뉴에서 [ VCS ] >> [ Import into Version Control ] >> [ Share Project on GitHub ]  를 선택해서 깃 허브에 프로젝트를 연동합니다.





레포지터리 이름과 리모트 이름도 설정해줍니다.


전 그냥 디폴트 값으로 했습니다. 







그 다음 메뉴에 있는 VCS Commit 버튼을 눌러줍니다.







아래와 같이 파일들이 모두 올라온 것을 확인하고 


우하단에 Commit (확정) and Push (발행) 을 눌러줍니다.


Commit 만 할 경우 로컬 저장소에만 저장되고 Push 를 해줘야 GitHub에 발행됩니다.






깃허브에 성공적으로 공유되었다는 메시지를 확인하고









마지막으로 깃허브 홈페이지에서 방금 Push 한 파일을 확인해주시면 됩니다.!



출처: https://liveonthekeyboard.tistory.com/entry/안드로이드-스튜디오-GitHub-연동과-add-commit-push-개념 [키위남]

출처:https://ykyh.tistory.com/4


우선 안드로이드M 이 공개 되면서 여러 변경되거나 추가된 내용 중에서 개인적으로 개발자가 가장 신경써야 할 부분은 "권한"에 대한 부분이라고 생각되어 퍼미션에 대해 제일 먼저 다루겠습니다.


Android Developer

우선 자세한 내용은 Android Developer 사이트에서 자세히 설명해 주고 있고, 안드로이드M에 대해서는 무려 한글페이지를 제공해 주고 있습니다!!!!!!!!!!!!!!!


안드로이드M 이하 버전의 경우 특정 기능을 사용하기 위해서 <uses-permission..>만 정의 하고 설치 시 안드로이드 인스톨러에서 사용자에게 고지 하도록 되어 있습니다.시 안드로이드 인스톨러에서 사용자에게 고지 하도록 되어 있습니다., 


안드로이드M 에서는 퍼미션을 사용하는 시점에 사용자에게 퍼미션 사용여부를 고지 하고 사용자가 동의해야만 사용할 수 있습니다

모든 퍼미션이 이렇게 사용해야 되는 것은 아니고, 개인정보와 관련된 몇몇 퍼미션에 관해서 별도의 처리를 해줘야 합니다.


Developer 사이트에 정의되어있는 별도로 퍼미션 처리를 해줘야하는 퍼미션은 다음과 같습니다.


권한 그룹권한
android.permission-group.CALENDAR
  • android.permission.READ_CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
  • android.permission.CAMERA
android.permission-group.CONTACTS
  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.READ_PROFILE
  • android.permission.WRITE_PROFILE
android.permission-group.LOCATION
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE
  • android.permission.RECORD_AUDIO
android.permission-group.PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
  • android.permission.BODY_SENSORS
  • android.permission.USE_FINGERPRINT
android.permission-group.SMS
  • android.permission.SEND_SMS
  • android.permission.RECEIVE_SMS
  • android.permission.READ_SMS
  • android.permission.RECEIVE_WAP_PUSH
  • android.permission.RECEIVE_MMS
  • android.permission.READ_CELL_BROADCASTS


개발 방법

테스트로 아래의 두 퍼미션을 정의하며, "android.permission.CALL_PHONE" 의 경우 사용자의 확인이 필요한 퍼미션이고, "android.permission.ACCESS_WIFI_STATE"의 경우 확인이 필요 없는 퍼미션 입니다.


<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>


앱을 설치 하고 안드로이드 설정에서 애플리케이션에셔 보면 CALL_PHONE 에 관해서는 사용자가 퍼미션을 ON/OFF 처리 할 수 있도록 되있습니다. 

 

이제 우리가(개발자들) 해야할일이 생겼죠...!

1. 설정에서 퍼미션 사용이 ON으로 되어있는지 확인

 - checkSelfPermission(String permission)


2. 퍼미션 사용 요청

 - requestPermissions(String[] permissions, int requestCode)

requestPermissions 메서드를 호출 하면 팝업이 뜨면서 사용자에게 퍼미션을 허용을 요청 하게 됩니다.

사용자가 동의 버튼을 선택 할 경우 앱 설정에 퍼미션이 ON으로 바뀌게 됩니다.


 


3. 사용자 응답에 따른 결과 받기

 -  onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)

PERMISSION_GRANTED 응답을 받았다면, 요청한 퍼미션에 대한 작업을 하시면 됩니다.


예제 소스

아래 테스트 예제를 보시면 쉽게 이해 되실겁니다.


 private final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1000;

private View.OnClickListener buttonListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        switch (view.getId()) {
            case R.id.BT_CALL_PHONE :

                if (checkSelfPermission(Manifest.permission.CALL_PHONE)
                        != PackageManager.PERMISSION_GRANTED) {
                    requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
                            MY_PERMISSIONS_REQUEST_CALL_PHONE);
                    return;
                } else {
                    callPhone();
                }
                break;

            default:
                break;
        }

    }
};

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_CALL_PHONE: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! do the
                // calendar task you need to do.
                callPhone();
            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(this, "NOT GRANTED", Toast.LENGTH_LONG).show();
            }
            return;
        }

        // other 'switch' lines to check for other
        // permissions this app might request
    }
}
private void callPhone() {
    Intent i = new Intent(Intent.ACTION_CALL, Uri.parse("tel:010-1234-5678"));
    startActivity(i);
}

 



출처: https://ykyh.tistory.com/4 [요콩 공부방]



+ Recent posts