1. 문제발생

리엑트로 만들어진 페이지에서 윈도우 팝업을 오픈하고, 해당 팝업 내부에서 이벤트를 통해 부모창에서 추가 팝업을 열고자 했는데 팝업이 차단되어있어 팝업이 open되지 않는 상황 >

사용자에게 해당 상황에 팝업이 차단되어있다는 사실을 고지하기 위해 부모창에서 alert을 띄웠지만 열려있는 팝업때문에 사용자에게 노출이 되지 않는 문제가 발생하였다.

 

2. 해결방법

첫번째 팝업을 ref로 관리하여 postMessage를 통해 팝업에 직접적으로 alert출력

 

3. 코드

// 첫번째팝업 ref에 할당
popElement.current = window.open('', '_blank', `width=${width},height=${height},top=${top},left=${left}`);

// 팝업 코드 할당
let element = <사용자 작성 페이지 컴포넌트 />
const htmlString = ReactDOMServer.renderToString(element);

let script = `
              <script>
                  ...
                 //클릭이벤트 postMessage (두번째팝업 오픈이벤트)
                  const info = document.querySelectorAll('.clickBtn');
                  info.forEach(el => {
                    el.addEventListener('click', function() {
                      const id = el.getAttribute('id');
                      window.opener.postMessage({ type: 'selectedItem', id }, '*');
                    });
                  });
				// alert postMessage (두번째팝업 null일경우 alert 이벤트)
                  window.addEventListener('message', function(event) {
                    if (event.origin === window.origin) {
                      alert(event.data);
                    }
                  });
                  
                </script>
                `;

      let printHtml = htmlString + script;

      popElement.current.document.writeln(printHtml);
      
  // 두번째팝업 오픈이벤트 분기
  useEffect(() => {
    const handleMessage = (event) => {
      if (event.data.type === 'selectedItem') {

        두번째팝업func(event.data.id);

      }
    };
    window.addEventListener('message', handleMessage);

    return () => {
      window.removeEventListener('message', handleMessage);
    };
  }, []);
  
  
  // 두번째팝업 오픈이벤트
  const printWindow = window.open('', '_blank', `width=${width},height=${height},top=${top},left=${left}`);
    // 두번째팝업 null일경우 예외처리
    if (!printWindow || printWindow.closed || typeof printWindow.closed === 'undefined') {
      if (popElement.current) {
        popElement.current.postMessage("Pop-ups are blocked. Please disable your pop-up blocker and try again.");
      }

      return;
    }

 

프로젝트 진행 중 서버로 param을 전송할 때에 특정 데이터의 입력 여부 확인 기능을 구현할 때 사용한 함수 내용을 정리하겠다.

 

[조건]

1. 특정데이터의 Null, 공백, List length, 특정 값 등을 Filtering 해주는 기능 구현

 

// 확인 부분. result = boolean
let param = {
	id: ...,
        pw: ...,
        addr: ...,
        name: ...,
        ..
        ..
        ..
    }

let isEmpty = isAllFieldsNullOrEmpty(param, ["addr", "name", "...", ...]/* 제외할 키 입력 */);


// null check 함수
const isAllFieldsNullOrEmpty = (param, excludeKeys = []) => {
    return Object.entries(param)
      .filter(([key]) => !excludeKeys.includes(key))  // 제외할 키들을 필터링
      .every(([key, value]) => 
        value === null || 
        value === "" || 
        value.length === 0 || /* array 데이터일 경우 */ 
        (key === 특정key && value === 특정value)
      );
  }

 

위 함수내용 기억해서 나중에 찾아 헤메지 말자....!!!!

프로젝트 진행 중 grid의 데이터 중 체크된 대상의 특정 데이터 값의 합을 구하는 기능을 구현할때 사용한 

함수 내용을 정리하겠다.

 

[조건]

1. 그리드 데이터 중 선택된 row의 count 중 특정 값이 같지 않은 데이터의 합을 구함

2. 그리드 데이터 중 선택된 row의 count를 구함

3. 그리드 데이터 중 선택된 row의 특정 데이터 값의 합(float)을 구함

 

[1]
result = checkedList.map(el => el.rowData)
		.filter((el, idx, callback) => 
        	idx === callback.findIndex(el2 => el2.id === el.id)
	).length;


[2]
result = checkedList.map(el => el.rowData)
		.reduce((total, row) => total/* 합산되는 data */ + row.invQty, 0/* total의 init value*/);


[3]
result = checkedList.map(el => el.rowData)
		.reduce((total, row) => total + parseFloat(row.amount.replace(/,/g, '')), 0);
        //replace사용은 해당 amount데이터가 자릿수 나눔이 되어 문자열 형태로 되어있기 때문

 

위 코드 활용해서 나중에 찾아헤메지 말자...!

 

1. 하기의 사이트 접속 후 마음에드는 음원 다운로드

https://soundeffect-lab.info/

 

効果音ラボ - 商用無料、報告不用の効果音素材をダウンロード

2400音以上の音源を掲載したフリー効果音サイト。品質にこだわっており、テレビなどのプロの音響現場でも使われています。

soundeffect-lab.info

 

 

2. 다운로드한 파일을 wav 파일로 변환(mp3(음원파일 확장자명) to wav 검색)

https://convertio.co/kr/mp3-wav/

 

MP3 WAV 변환 (온라인 무료) — Convertio

mp3 파일(들) 업로드 컴퓨터, Google Drive, Dropbox, URL에서 선택하거나 이 페이지에서 드래그하여 선택해 주세요.

convertio.co

 

 

3. Unity 내부에서 제작하고있는 Assets 폴더 내부에 변환한 wav 파일 삽입

 

4. Sound를 삽입할 객체에 Audio Source 컴포넌트 추가 후 wav 파일 업로드

 

5. Play on Awake 체크 해제(플레이시 바로 Sound가 출력되길 원하면 체크)

 

6. 다음과같이 특정상황에서 Sound가 출력되도록 코드 작성

if(Input.GetMouseButtonDown(0)) // 0 = 왼클릭
{
    GetComponent<AudioSource>().Play();
    rb.velocity = Vector2.up * jumpPower; // 기본값 (0,1)
}

 

 

정수 N의 약수의 개수를 구할 때 1부터 N까지 반복문을 통해서 약수를 구하는 게 아닌,

Math.sqrt(N) 함수를 사용하여 간단한 시간복잡도로 약수의 개수를 구할 수 있다.

 

 

 

정답 코드

class Solution {
    public int solution(int left, int right) {
        int answer = 0;
        for(int i=left; i<=right; i++){
            if(i % Math.sqrt(i) != 0) answer += i;
            else answer -= i;
        }
        
        return answer;
    }
}

 

*** 결과 ***

정수 N % N의 제곱근 == 0일 경우 N의 약수는 홀수개 이며, 

정수 N % N의 제곱근 != 0일 경우 N의 약수는 짝수개 이다.

'알고리즘' 카테고리의 다른 글

JAVA - 1부터 n사이에 소수의 개수 구하기  (0) 2023.12.18

 

▼ 기존 작성 코드

class Solution {
    public int solution(int n) {
        int answer = 0;
        for(int i=2; i<=n; i++){
            int cnt = 0;
            for(int j=1; j<=i; j++){
                if(i % j == 0) cnt ++;
                if(cnt > 2) break;
            }
            if(cnt == 2) answer++;
        }

        return answer;
    }
}

 

위 코드로 실행하였을때, 코드 자체는 성공하였으나 시간복잡도가 높아 통과되지 않는 케이스가 발생하였다.

 

 

▼ 수정된 코드

import java.util.*;

class Solution {
    public int solution(int n) {
        boolean[] isPrime = new boolean[n + 1];
        Arrays.fill(isPrime, true);

        isPrime[0] = isPrime[1] = false; // 0과 1은 소수가 아님

        for (int i = 2; i * i <= n; i++) {
            if (isPrime[i]) {
                for (int j = i * i; j <= n; j += i) {
                    isPrime[j] = false; // i의 배수는 소수가 아님
                }
            }
        }

        int count = 0;
        for (boolean prime : isPrime) {
            if (prime) {
                count++;
            }
        }

        return count;
    }
}

 

위 코드는 에라토스테네스의 체 알고리즘을 보고 작성한 코드이다.

해당 코드로 수정했을때 시간복잡도가 해결되어 모든 테스트 케이스에 통과할 수 있었다.

 

***************************************************************************************************************

에라토스테네스의 체 알고리즘 이란?

 

고대 그리스 수학자 에라토스테네스가 발견한 제곱근을 이용한 소수를 구하는 방법.

소수를 구하는 최적의 알고리즘이라고 합니다.

 

소수는 n의 배수가 아니고 입력받은 수를 그 수보다 작은 수들로 나누어서 떨어지면 소수가 아니다.

그러므로, 모두 나누어 볼 필요없이 n 제곱근 까지만 나누어서 떨어지면 소수가 아니다.

***************************************************************************************************************

'알고리즘' 카테고리의 다른 글

JAVA - 약수의 개수 구하기  (0) 2024.01.02

 

우선, 기존에 사용하던 퍼미션이 Android 13버전에 이르러서 다음과 같이 변경되었다.

// 기존 사용 Permission
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

// 세분화된 Permission
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

 

기존 제작된 앱에 변경사항이 생겨 릴리즈를 하려 하였으나, Android13 버전 추가로 인해 신규 정책이 생겨 릴리즈하지 못하는 상황이 발생해 다음과 같이 코드를 수정하였다.

 

1.  AndroidManifest.xml 파일에 다음과 같이 퍼미션 추가

<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" android:minSdkVersion ="33" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion ="33" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" android:minSdkVersion ="33" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

 

 

2. 퍼미션 전송 Activity 퍼미션 Array 코드 수정

//필요한 퍼미션 리스트
private val requiredPermissions = arrayOf(
        Manifest.permission.INTERNET,
        Manifest.permission.CAMERA,
        Manifest.permission.RECORD_AUDIO,
        Manifest.permission.MODIFY_AUDIO_SETTINGS,
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.CALL_PHONE
)

//새로추가한 내용(sdk33 업데이트 적용) -> 현재 타겟팅 sdk버전이 33이상일 경우 permision 세분화하여 추가
//33미만일 경우 기존의 permision 추가
        var result = ArrayList<String>(requiredPermissions.toList())
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
            result.add(Manifest.permission.READ_MEDIA_AUDIO)
            result.add(Manifest.permission.READ_MEDIA_VIDEO)
            result.add(Manifest.permission.READ_MEDIA_IMAGES)
        }else{
            result.add(Manifest.permission.READ_EXTERNAL_STORAGE)
            result.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}

 

 

3. 타겟팅 API 버전 수정 및 SDK 버전 수정

 

AndroidMainfest.xml --> toos:targetApi="33"

build.gradle --> compileSdk / targetSdk 33

 

 

sdk버전만 맞추어 개시하였을때는 세분화된 권한으로 인해 정상적으로 권한허용이 진행되지 않앗는데,

수정 후 확인해본 결과 정상적으로 권한 허용이 가능해졌다!!!!

'Android Studio' 카테고리의 다른 글

Android Studio로 App 정보 수정 및 Release  (0) 2023.06.09

1. 기본환경 설정

 

■ 기본 테마 변경(New UI)

 

 

■ 인코딩 타입 설정

 

 

■ Auto Import 설정 (코드 작성시 필요한 라이브러리 및 클래스 자동 import)

 

 

■ Match Case 옵션 해제 (코드 자동완성시 대소문자 구분 끄기)

 

 

■ Inable Annotation Processing 설정 (주석 처리기 기능)

 

>> 이후 Java(JDK) 및 메이븐 설정 !!

 

 

2. 유용한 플러그인

 

>> 현재 찾아본 유용한 플러그인은 위와같다. 더 사용하면서 찾아보자

'기타' 카테고리의 다른 글

인텔리제이 [IntelliJ] 설치하기  (0) 2023.11.15
VS Code 사용시 유용한 extension 모음  (0) 2023.05.15
작업환경 개선(eclipse)  (0) 2023.05.09

+ Recent posts