달력

12

« 2024/12 »

  • 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
반응형

웹 개발을 하다 보면 보통 처음엔 퍼블리싱을 받지만

어쩔 수 없이 추가 개발이 들어와 기존에 있던 ui를 확장하여 새로운 ui 작업을 하기도 한다.

ui 고칠 일이 많거나 새로운 아이콘이 필요하다거나 잘 모르겠으면

퍼블리셔 분에게 요청하겠지만 간단한 것은 빠르게 내 선에서 해결하는 편이다.

 

이것도 그런 일 중 하나로, 관리자 페이지 특정 목록에서 엑셀 일괄 등록 기능이 새로 추가되는 일이었다.

엑셀 파일로 데이터를 업로드하여 진짜 테이블에 넣기 전에 임시 테이블에 넣어 확인하는 ui가 있었는데

엑셀로 등록하다 보니 나중에 행의 개수가 많아져 header가 고정되는 편이 좋을 것 같아 그렇게 작업했다.

 

처음엔 그냥 y축만 움직여서 작업하면 되어서 css로 충분히 작업이 가능하였으나

x축이 필요한 테이블이 생기게 되어 jQuery를 이용하는 아래 결과물이 나오게 되었다.

<style>
#userTbl {
  	width: 600px;
	height: 200px;
  	overflow-y: auto;
}
  	
#userTblHead {
  	width: 600px;
  	overflow-x: hidden;
}
  	
#userTbl table {
  	border-top: 0px;
}
  	
#userTblHead table {
  	overflow: hidden;
  	border-top: 2px solid #aaa;
  	border-bottom: 1px solid #aaa;
}
  	
.tblWrap table {
  	width: 100%;
  	border-spacing: 0;
  	border-width: 1px 0;
  	border-collapse: collapse;
  	table-layout: fixed;
}

.tblWrap table thead th {
	background: #eee;
}

.tblWrap table td {
	text-align: center;
	border-bottom: 1px solid #aaa;
}

.tblWrap table td.left {
	text-align: left;
	padding-left: 10px;
}

.tblWrap table th:not(:last-child), table td:not(:last-child) {
    border-right: solid 1px #aaa;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
var sl = 0;
$(function(){
	$.fn.hasYScrollBar = function() {
	    return (this.prop("scrollHeight") == 0 && this.prop("clientHeight") == 0)
	            || (this.prop("scrollHeight") > this.prop("clientHeight"));
	};

	$.fn.hasXScrollBar = function() {
	    return (this.prop("scrollWidth") == 0 && this.prop("clientWidth") == 0)
	            || (this.prop("scrollWidth") > this.prop("clientWidth"));
	};
	
	$("#userTbl").scroll(function(event){
		// data 테이블 x축 스크롤을 움직일 때header 테이블 x축 스크롤을 똑같이 움직인다
		if (sl != $("#userTbl").scrollLeft()) {
			sl = $("#userTbl").scrollLeft();
			$("#userTblHead").scrollLeft(sl);
		}
	});
	
	if ($("#userTbl").hasYScrollBar()) {
		//y축 스크롤이 있으면 스크롤 넓이인 17px만큼 header 마지막 열 크기를 늘린다
		$("#userTblHead colgroup col:last-child").width($("#userTbl colgroup col:last-child").width() + 17);
	} else {
		$("#userTblHead colgroup col:last-child").width($("#userTbl colgroup col:last-child").width());
	}
});
</script> 
<div class="tblWrap">
	<div id="userTblHead">
		<table>
			<!-- col의 width를 %가 아닌 px 단위로 정확히 지정해야 두 테이블이 하나의 테이블 처럼 보인다 -->
			<colgroup>
				<col style="width:45px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:150px">
				<col style="width:200px">
				<col style="width:130px">
				<col style="width:130px">
			</colgroup>
			<thead>
				<tr>
					<th>No</th>
					<th>이름</th>
					<th>부서</th>
					<th>직급</th>
					<th>아이디</th>
					<th>전화번호</th>
					<th>이메일</th>
					<th>생년월일</th>
					<th>입사일</th>
				</tr>
			</thead>
		</table>
	</div>
	<div id="userTbl">
		<table>
			<colgroup>
				<col style="width:45px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:150px">
				<col style="width:200px">
				<col style="width:130px">
				<col style="width:130px">
			</colgroup>
			<tbody>
				
				<tr>
					<td>1</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>2</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>3</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>4</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>5</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>6</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>7</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>8</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>9</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
			</tbody>
		</table>
	</div>
</div>

 

- y축 있을 때

No 이름 부서 직급 아이디 전화번호 이메일 생년월일 입사일
1 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
2 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
3 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
4 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
5 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
6 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
7 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
8 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
9 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08

 

- y축 없을 때

No 이름 부서 직급 아이디 전화번호 이메일 생년월일 입사일
1 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
2 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
3 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08

 

아시다시피 html table은 header가 기본적으로 고정되지 않지만 위와 같이 편법을 쓰면 가능하다.

table header를 고정시키는 편법으로는 여러 가지 방법이 있으나

위 방법처럼 접근성엔 좋지 않은 header 테이블과 data 테이블을 나눈 이유는

내가 적용하려는 웹이 관리자 페이지이므로 접근성이 크게 상관없고,

저 방법으로 하면 ie와 Chrome 둘 다 열을 나누는 선이 있어도 y축이 있든 없든 예쁘게 보이기 때문이다.

반응형
:
Posted by 리샤씨
반응형

인터넷에 ionic2, Angular 뒤로 가기 버튼에 대하여 검색하면

형식적으로 뒤로 가기 버튼 두 번 누르면 ionic 앱이 꺼지게 하는 기능이나,

팝업을 열어서 앱을 종료할 것인지 확인하는 등 아주 기본적인 뒤로 가기 버튼 동작을 알려준다.

 

그러나 개발을 하다 보면 뒤로 가기 종료 동작은 메인(root)에서만 가능해야 하며

(메인이 아니면 보통 이전 화면으로 가는 것이 맞다)

이미 팝업이 켜져 있는 상황이라든가

(종료 동작이나 그냥 이전 화면으로 가는 것보다는 팝업부터 끄는 것이 자연스러움)

메뉴가 열려있는 상황

(역시나 종료 동작이나 그냥 이전 화면으로 가는 것보다는 메뉴부터 닫는 것이 자연스러움),

평범하게 nav로 이동하지 않고 view로 연 경우 등 고려할 것들이 많아진다.

 

아래 방법보다 더 쉬운 방법이 있을 수 있겠지만

작성 당시 ionic에 대한 자료가 충분치 않아 직접 몇 번의 실험 끝에 작성된 코드를 공유한다.

 

다른 곳(root page 정도)에 작성해도 무리 없지만 나는 app.component.ts에 작성하였다.

import { Component } from '@angular/core';
import { Platform, App, NavController, MenuController, ToastController } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { HomePage } from '../pages/home/home';
@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  private navCtrl: NavController;
  rootPage:any = HomePage;
  mFlag: boolean = false;
  
  constructor(platform: Platform, 
              statusBar: StatusBar, 
              public app: App, 
              public menu: MenuController,
              public toastCtrl: ToastController,
              splashScreen: SplashScreen) {
    platform.ready().then(() => {
      statusBar.styleDefault();
      splashScreen.hide();

      platform.registerBackButtonAction(() => {
          try {
                let nav = this.app.getActiveNav();

                let view = nav.last();
                const portal = app._appRoot._getPortal();

                if (this.menu.isOpen() == true) {
                    this.menu.close();
                } else if(portal.length() != 0) {
                    this.app._appRoot._overlayPortal.getActive().dismiss();//팝업 창이 뜬게 있다면 팝업 창도 닫아줌 
                } else if (view.isOverlay) {
                    view.dismiss({});
                } else if (view.isFirst()) { //root에서만 되게하기
                    if (!this.mFlag) {
                        this.mFlag = true;
                        let toast = toastCtrl.create({
                                        message: "뒤로 버튼을 한 번 더 누르시면 앱이 종료됩니다.",
                                        duration: 3000,
                                        position: "middle",
                                        cssClass: "toast-default"
                        });
                        toast.present();

                        //3초 기다리기  
                        setTimeout(() => {
                            this.mFlag = false;
                        }, 3000);
                    } else {
                        platform.exitApp();
                    }
                } else {
                    nav.pop();
                }
            } catch (e) {
                console.log("back action listener error :" + e);
            }
        });
    });
  }
}

반응형
:
Posted by 리샤씨
2020. 1. 3. 09:30

Chart.js Pie 데이터 값 출력 개발/Chart.js2020. 1. 3. 09:30

반응형

어제 통계를 살펴보니, pie 데이터 값 출력이라는 정보를 찾는 키워드를 발견하여 글 작성합니다.

piece label이라는 Chart.js 확장 플러그인을 사용하면 되는데,

https://github.com/emn178/chartjs-plugin-labels/tree/master/src

위 링크를 타고 들어가면 js가 있습니다.

 

사용법은 아래와 같습니다.

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js"></script>
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="/com/js/Chart.PieceLabel.js"></script> <!-- your piecelabel -->
<script type="text/javascript">
var num = Math.random();
  var data = {
      labels: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"],
      datasets: [
          {
              data: [
                Math.random(),
                Math.random(), 
                Math.random(), 
                Math.random(), 
                Math.random(), 
                Math.random(), 
                Math.random(),
                Math.random(),
                Math.random(),
                Math.random()
              ],
              backgroundColor: [
      	        "#f79546",
       	        "#9bba57",
                "#4f81bb",
                "#5f497a",
                "#a94069",
                "#ff5f34",
                "#41774e",
                "#003663",
       	        "#49acc5",
       	        "#c0504e"
              ],
	          borderWidth: 0,
	          label: "Dataset 1"
          }]
  };
   
  window.onload = function() {
    var ctx8 = $('#chart8').get(0).getContext("2d");
    window.theChart8 = new Chart(ctx8, {
        type: 'pie',
        data: data,
        options: {
                responsive: true,
                legend: false,
                maintainAspectRatio : false,
                animation: false,
                pieceLabel: {
                  mode:"label",
                  position:"outside",
                  fontSize: 11,
                  fontStyle: 'bold'
               }
        }
    });
</script>
<div style="width:150px">
  <canvas id="chart8"></canvas>
</div>

간단히 설명하자면, options의 pieceLabel이 Pie 차트의 데이터 값을 표시하는 기능입니다.

mode에 따라 label/value/percentage(default)/image를 표시할 수 있고

position에 따라 default(default)/border/outside 값이 표시될 위치를 지정할 수 있습니다.

position : default / outside

또한, Pie 차트뿐만 아니라 Doughnut, polarArea, Bar 차트에서도 사용 가능합니다.

 

출처 : https://stackoverflow.com/questions/42164818/chart-js-show-labels-on-pie-chart

반응형
:
Posted by 리샤씨
반응형

ionic2, Angular에서 AndroidManifest.xml을 수정할 일이 생겼었다.

ionic2, Angular에서 AndroidManifest.xml를 직접 건드리면 나중에 개발자가 바뀐다거나 platform을 다시 추가할 때,

다시 같은 작업을 해줘야 하는 일이 생기기 때문에 (platform 쪽 소스는 Git이나 svn에 올라가지 않기 때문)

매우 꺼려지는 일 중에 하나였다.

그래서 찾아보니 다행히도 config.xml에서 config-file, edit-config 등등 태그를 이용하면

platform에 있는 파일(xml, plist 등)도 수정할 수 있음을 확인하였다.

 

그런데 여기서 문제가 하나 발생했다.

config-file 태그를 cordova 공식 홈페이지 대로 따라 해서 적용해보았는데 아래와 같은 오류가 난 것이다.

Execution failed for task ':app:mergeDebugResources'.
> java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: Android resource compilation failed
  {{ionic_app_route}}\platforms\android\app\src\main\res\xml\config.xml:80: error: unbound prefix.

구글에 검색해보니 android 네임스페이스를 선언하지 않아서 생긴 문제라

간단히 config.xml 최상위 태그인 widget에

xmlns:android="http://schemas.android.com/apk/res/android" 를 추가하면 되는 일이었다.

 

참조 : https://cordova.apache.org/docs/en/latest/plugin_ref/spec.html#edit-config                     https://stackoverflow.com/questions/18871005/error-parsing-xml-unbound-prefix-on-library

반응형
:
Posted by 리샤씨
반응형

다음 오류는 ionic2, Angular에서 firebase, media, camera 등등의 플러그인을 설치한 뒤,

안드로이드에 넣기 위해 빌드해보니 발생한 오류이다.

com.android.build.api.transform.TransformException: Error while generating the main dex list: 
  Error while merging dex archives: 
  Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes. 
  Program type already present: android.support.v4.app.INotificationSideChannel$Stub$Proxy

해결하기 위해 찾아보니 Cordova 프로젝트에 Android 지원 라이브러리 및 AndroidX를 모두 참조하는 플러그인/라이브러리가 포함된 경우 Android 빌드가 실패한다고 한다.

그래서 이를 보완해주는 cordova-plugin-androidx-adapter를 추가 설치하니 정상적으로 빌드가 성공되었다.

 

참조 : https://github.com/dpa99c/cordova-plugin-androidx-adapter

반응형
:
Posted by 리샤씨
반응형

2019/07/24 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (1) : toast

 

ionic에서 모바일 접근성 적용하기 (1) : toast

최근 ionic앱에 모바일 접근성(Mobile Accessibility)을 적용할 일이 생겼다. ionic에는 크게 ionic-angular, ionic-native로 나뉘어 지는데 플러그인들이 많은데 toast도 그중 하나다. 나는 평소 ionic을 테스트..

risha-lee.tistory.com

↑위 글과 연결된 글입니다.

지난번에 ionic2, Angular에서 toast를 모바일 접근성을 위해 작업한 적이 있었다.

그러나 그 작업은 ios의 voice over에서는 원하는 대로 동작하지 않았고, 다른 방법이 필요해졌다.

그래서 찾은 것이 MobileAccessibility의 speak이다.

사실 먼저 찾은 것은 swift에서 사용하는 코드였는데 ionic에서 비슷한 코드를 찾아보니 MobileAccessibility에 있었다.

 

코드는 다음과 같다.

 

1. phonegap-plugin-mobile-accessibility를 설치한다.

$ ionic cordova plugin add phonegap-plugin-mobile-accessibility

 

2. 읽기를 원하는 지점에 해당 코드를 삽입한다.

if ((<any>window) && (<any>window).MobileAccessibility) {
  setTimeout(()=>{
    (<any>window).MobileAccessibility.speak(msg);
  }, 1000);
}

msg가 읽기를 원하는 내용이다.

1초 정도 늦게 읽는 것이 원래 읽으려던 것을 읽고 원하는 내용(msg)을 읽도록 하기가 좋았다.

(1초 정도 늦게 읽게 하지 않으면 내가 원하는 내용을 읽다가 원래 읽으려던 것을 읽어버려서 내가 명령한 것이 무시되는 경우를 경험했다)

 

참고 : https://stackoverflow.com/questions/31776907/is-there-any-way-to-have-voiceover-read-a-label-on-command

반응형
:
Posted by 리샤씨
반응형

최근 회사에서 MSA를 도입하면서 keycloak을 처음 사용하게 되었다.

검색해보면 java에서 keycloak을 사용하는 법은 여러 가지로 많이 나오지만 

ionic에서 keycloak을 사용하는 법은 쓸데없이 플러그인을 사용해서 하라고 한다.

나도 처음엔 플러그인으로 해보려 했지만(플러그인으로는 실패하였다) 그보다 간단히 되는 방법을 찾았다.

원래 java 소스였는데 그냥 http 통신하는 거라 ionic에도 쉽게 적용되었다.

 

이건 ionic-angular http만으로도 작동되지만, 혹시 필요한 사람을 위해 ionic-native http 버전도 함께 공유한다.

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Http, RequestOptions, Headers } from '@angular/http';
import { HTTP } from '@ionic-native/http';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  keycloakConfig = {
        url: 'https://your_keycloak_url/auth',
        realm: 'your_realm',
        client_id: 'your_client_id',
        client_secret : 'your_client_secret'
    };
    
  constructor(public http: Http,
                public n_http: HTTP,
                public platform: Platform) {
                
    this.getToken({email : "email@email.com"
                   pswd : "password!"}).then(res => {
      console.log(res);
    }).catch(error => {
      console.log("Error", error);
    });
  }

  getToken(userData) {
    if (this.platform.is('cordova') == false){ 
      return new Promise((resolve, reject) => {
        var body = "grant_type=" + "password"+
                   "&client_id=" + this.keycloakConfig.client_id +
                   "&username=" + userData.email +
                   "&password=" + userData.pswd +
                   "&client_secret=" + this.keycloakConfig.client_secret;
        var headers = new Headers();
        headers.append('content-type','application/x-www-form-urlencoded');
        let options = new RequestOptions({ headers:headers });
                
        this.http.post(this.keycloakConfig.url+'/realms/'+this.keycloakConfig.realm+'/protocol/openid-connect/token', body, options).timeout(5000).subscribe(res => {
            resolve(res.json());
          }, (err) => {
            reject(err);
          });  
        });
    } else {
      return new Promise((resolve, reject) => {
        var body = {grant_type: "password",
                    client_id: this.keycloakConfig.client_id,
                    username: userData.email,
                    password: userData.pswd,
                    client_secret: this.keycloakConfig.client_secret};
        this.n_http.setSSLCertMode('nocheck');
        this.n_http.setRequestTimeout(5);
        this.n_http.setHeader('*', 'content-type', 'application/x-www-form-urlencoded');
        this.n_http.post(this.keycloakConfig.url+'/realms/'+this.keycloakConfig.realm+'/protocol/openid-connect/token', body, {}).then(res =>{
            resolve(JSON.parse(res.data));
          }).catch(err =>{
            reject(err);
          });
        });
      }
    }
  }
}

 

이런 식으로 body만 아래 코드로 변경하여 토큰 리프레시도 가능하다.

var body = "grant_type=" + "refresh_token"+
           "&client_id=" + this.keycloakConfig.client_id +
           "&refresh_token=" + "your_refresh_token" +
           "&client_secret=" + this.keycloakConfig.client_secret;

 

 

 

*참고 Java source

String uri = "http://localhost:7080/auth/realms/{RealmName}/protocol/openid-connect/token";

HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(uri);
post.setHeader("User-Agent",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
List<BasicNameValuePair> urlParameters = new ArrayList<BasicNameValuePair>();
urlParameters.add(new BasicNameValuePair("grant_type", "password"));
urlParameters.add(new BasicNameValuePair("client_id", {ClientName}));
urlParameters.add(new BasicNameValuePair("username", {UserName}));
urlParameters.add(new BasicNameValuePair("password", {Password}));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
HttpResponse response = client.execute(post);
System.out.println("Response Code : " + response.getStatusLine().getStatusCode());
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line1 = "";
while ((line1 = rd.readLine()) != null) {
	result.append(line1);
}
System.out.println(result);

 

출처 : https://stackoverflow.com/questions/39356300/avoid-keycloak-default-login-page-and-use-project-login-page

반응형
:
Posted by 리샤씨
반응형

2019/07/24 - [개발/ionic2, Angular] - ionic에서 모바일 접근성 적용하기 (1) : toast

 

ionic에서 모바일 접근성 적용하기 (1) : toast

최근 ionic앱에 모바일 접근성(Mobile Accessibility)을 적용할 일이 생겼다. ionic에는 크게 ionic-angular, ionic-native로 나뉘어 지는데 플러그인들이 많은데 toast도 그중 하나다. 나는 평소 ionic을 테스트..

risha-lee.tistory.com

↑위 글과 연결된 글입니다.

 

이전에 설명했던 ionic-angular http의 문제를 수정하는 법을 작성하겠다.

 

원인은 인증서 문제라면서 앱에 인증서를 고정하라는 답변을 발견하였다.

하지만 native 소스를 직접 건드리는 것은 좋은 방법이 아닌 것 같아 더 찾아본 결과, 

가장 효율적으로 보이는 https release error 수정하는 법은 다음과 같다.

(ionic-angular http를 이미 사용하고 있다고 가정하고 코드를 작성하였다)

 

2019/01/15 - [개발/ionic2, Angular] - Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response. error 해결법

그리고 위 포스팅에서 쓴 것과 달리 간혹 핸드폰에서도 CORS 오류가 나는 현상을 발견하였다.

이 문제도 아래 코드로 해결되는 것을 확인하였다. (디바이스에서 약간 디버깅이 어렵다는 것 말고는 여러모로 이득이다)

=> https://로 시작하는 URI를 제대로 동작시키지 못하는 이유는 서버에서 SSL을 제대로 적용 못해서였고 서버에서 제대로 적용해주면 ionic-angular http를 사용해도 apk를 release 했을 때 제대로 동작함을 확인했음

비슷한 이유로 CORS 오류도 서버 문제일 가능성이 높음

디버깅이 어려우므로 정말 서버를 수정할 수 없는 경우 이외엔 아래의 소스를 사용하지 않을 것 같음

그래도 필요한 경우가 생길 수도 있으니 소스는 삭제하지 아니함 (2020. 09. 03)

참고 : forum.ionicframework.com/t/ionic-native-http-ngx-v-s-angular-common-http-which-should-be-used-in-an-ionic4-app/169629/8

 

1. ionic-native http를 설치한다.

$ ionic cordova plugin add cordova-plugin-advanced-http
$ npm install --save @ionic-native/http

 

2. app.module.ts에서 ionic-native http providers에 넣는다.

import { HTTP } from '@ionic-native/http';

@NgModule({
   .....
providers: [
     .....
     HTTP
  ]
})

 

3. ts 파일을 수정한다.

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Http } from '@angular/http';
import { HTTP } from '@ionic-native/http';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
    url:string = "your_server_url";
    page_index: number = 1;
   
    constructor(public platform: Platform,
                public http: Http,
                public n_http: HTTP) {
      this.goGetNoti();
    }
    
    goGetNoti() {
        var param = "?page_index=" + this.page_index;
        this.getNoti(param).then(data => {
          console.log("getNoti", data);
          var _data:any = data;
                
          if (_data.isOk == 'Y') {
            // success
          } else {
            // server error
          }
        }).catch(error => {
            console.log("Error", error);
        });
    }
    
    public getNoti(param: string) {
       if (this.platform.is('cordova') == false){ 
            return new Promise((resolve, reject) => {
                this.http.get(url+'/v1/noti' + param).timeout(5000).subscribe(res => {
                    resolve(res.json());
                }, (err) => {
                    reject(err);
                });  
            });  
        } else {
            return new Promise((resolve, reject) => {
                this.n_http.setSSLCertMode('nocheck');
                this.n_http.setRequestTimeout(5);
                this.n_http.get(url+'/v1/noti' + param, {}, {}).then(res =>{
                    resolve(JSON.parse(res.data));
                }).catch(err =>{
                    reject(err);
                });
            });
        }
    }
}

(보통 getNoti와 같이 동작하는 함수는 다른 ts에 넣고 사용하기 때문에 getNoti와 goGetNoti로 분리하였다)

 

this.n_http.setSSLCertMode('nocheck'); 이 부분이 SSL 확인하지 않게 해주는 부분인듯하다.

찾아보았으나 아쉽게도 ionic-angular http에서는 ionic-native http처럼 SSL 확인을 하지 않아도 되는 기능이 없다.

그래서 앞으로 http onic-angular, ionic-native 분기 코딩은 계속될 거 같다.

 

보안 문제를 살짝 생각해봤는데 보통 서버도 같이 개발해서

이미 인증된 서버이므로 위와 같은 방법을 써도 문제는 없을 것 같다.

=> 위와 같은 이유로 취소선 추가

 

참고 : https://stackoverflow.com/questions/44833534/http-requests-fails-only-while-releasing-android-apk

https://forum.ionicframework.com/t/https-post-requests-not-working-in-release-build/154099/3

 

반응형
:
Posted by 리샤씨


반응형
반응형