"I/Glide: Root cause (1 of 1) javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found."
WebView webView = findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true); // 자바스크립트 사용여부
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); // 자바스크립트가 창을 자동으로 열 수 있게할지 여부
webView.getSettings().setLoadsImagesAutomatically(true); // 이미지 자동 로드
webView.getSettings().setUseWideViewPort(true); // wide viewport 설정
// 설정값이 false인 경우, layout 너비는 디바이스 픽셀에 맞추어 설정된다.
// 값이 true이고 페이지에 뷰포트 메타 태그가 있으면 태그에 지정된 너비 값이 사용된다.
// 페이지에 태그가 없거나 너비가 없는 경우 넓은 뷰포트가 사용된다.
webView.getSettings().setLoadWithOverviewMode(true); //컨텐츠가 웹뷰보다 클때 스크린크기에 맞추기
webView.getSettings().setSupportZoom(false); // 줌설정
webView.getSettings().setBuiltInZoomControls(true); // 줌아이콘
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); // 캐시설정
// LOAD_CACHE_ELSE_NETWORK : 캐시 기간만료 시 네트워크 접속
// LOAD_CACHE_ONLY : 캐시만 불러옴 (네트워크 사용 X)
// LOAD_DEFAULT : 기본 모드, 캐시 사용, 기간 만료 시 네트워크 사용
// LOAD_NO_CACHE : 캐시모드 사용안함
// LOAD_NORMAL : 기본모드 캐시 사용 @Deprecated
webView.getSettings().setAppCacheEnabled(false); //앱내부의 캐시 사용 여부
webView.getSettings().setDomStorageEnabled(true); // 로컬 스토리지 사용여부
webView.getSettings().setAllowFileAccess(true); // 파일 액세스 허용 여부
webView.getSettings().setUserAgentString("app"); // 사용자 문자열 설정
webView.getSettings().setDefaultTextEncodingName("UTF-8"); // 인코딩 설정
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setBlockNetworkImage(false); // 네트워크를 통해 이미지리소스 받을지 여부
webView.getSettings().setSupportMultipleWindows(true); // 멀티윈도우를 지원할지 여부
// {@link WebChromeClient#onCreateWindow} must be implemented by the host application. -
webView.getSettings().setDatabaseEnabled(false); //database storage API 사용 여부
webView.getSettings().setAllowContentAccess(true); // 웹뷰를 통해 Content URL 에 접근할지 여부
// a class -> 내부에 @JavascriptInterface 메서드 구현
// webView.addJavascriptInterface(new a(this), "app");
webView.setWebChromeClient(new WebChromeClient());
webView.clearCache(true);
webView.loadUrl("https://kyome.tistory.com/"); //웹뷰 URL로드
class ViewHolder() {
// item을 구성하고 있는 View에 맞게 변수 생성
var textName:TextView? = null
var textOs:TextView? = null
var textColor:TextView? = null
// setter 생성
fun setNoteBook(noteBook: NoteBook){
textName?.text = noteBook.name
textOs?.text = noteBook.os
textColor?.text = noteBook.color
}
}
(2) ViewHolder 사용하기
이렇게 생성된 ViewHolder는
getView 메서드 내에서 사용된다.
이전에 View로 inflate 한 xml을
다시 inflate 하지 않기 위해 getView의 두 번째 매개변수를 활용한다.
두 번째 매개변수 convertView는
이전에 inflate 한 View를 그대로 전달한다.
즉, convertView가 null이라면 최초 생성이라는
말이기 때문에 Inflate를 수행한다.
위에서 만들어 놓은 ViewHolder class를
객체로 생성하고
이 객체에 Inflate 된 View를 매핑한다.
ViewHolder객체를 잘 생성했다면
Inflate 된 View에 tag의 값으로
저장하고 반환한다.
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
// return
val view:View
val getData = dataList[position]
val vh:ViewHolder
if (convertView == null){
// Inflating
view = LayoutInflater.from(parent?.context).inflate(R.layout.item,parent,false)
// 매핑해놓음
vh = ViewHolder()
vh.textName = view.textName
vh.textOs = view.textOs
vh.textColor =view.textColor
// view에 viewholder 저장
view.tag = vh
// 이벤트 생성
view?.setOnClickListener{
Toast.makeText(context,getData.toString(),Toast.LENGTH_SHORT).show()
}
}else {
view = convertView
vh = convertView.tag as ViewHolder
}
//값 매칭
vh.setNoteBook(getData)
return view
}
val spinner: Spinner = findViewById(R.id.spinner)
// Create an ArrayAdapter using the string array and a default spinner layout
// Spinner 생성
// Adapterter 생성
// (1) Context 넣음
// (2) 리소스에서 R.array.planets_array 배열을 데이터로 넣음
// (3) item layout 넣음
ArrayAdapter.createFromResource(
this,
R.array.planets_array,
android.R.layout.simple_spinner_item
).also { adapter ->
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Spinner에 adapter 연결
spinner.adapter = adapter
}
저는 맨 처음 에러메시지와 표시해주는 코드라인을 따라가보니 ③에서 문제가 생겼다고 생각이 들었습니다.
일단 어떤 에러때문에 어플리케이션이 작동을 안했는지 봐볼까요?
라는 메시지와 함께 그 아래로 쭉쭉.. 메시지를 출력해주더라고요 ㅠㅠ
다음의 내용들이 중요해보이는 메시지에요 세부 디렉토리는 잘라냈습니다
그런데 자세히 볼수록 ①, ②에서 문제가 있다는 생각이 들었고 찾아보니 FileUri 부분이 문제였습니다.
2. 해결
Android 7.0 부터 API정책의 변경
안드로이드 7.0 (누가) 부터 앱사이의 공유가 더 엄격해져서 file:// URI 가 직접 노출되지 않도록 content:// URI를 보내고
이에 대해서 임시 액세스 권한을 부여하는 방식으로 변경되었다고 합니다.
이에 대한 자세한 설명은 밑에 공식참고문서(구글번역기로 번역된 글입니다)를 보시됩니다.
앱 사이의 파일 공유
Android 7.0을 대상으로 하는 앱의 경우, Android 프레임워크는 앱 외부에서 file:// URI의 노출을 금지하는 StrictMode API 정책을 적용합니다. 파일 URI를 포함하는 인텐트가 앱을 떠나면 FileUriExposedException 예외와 함께 앱에 오류가 발생합니다.
애플리케이션 간에 파일을 공유하려면 content:// URI를 보내고 이 URI에 대해 임시 액세스 권한을 부여해야 합니다. 이 권한을 가장 쉽게 부여하는 방법은 FileProvider 클래스를 사용하는 방법입니다. 권한과 파일 공유에 대한 자세한 내용은 파일 공유를 참조하세요.