오늘은 힘든 일요일이었으니 쉽고빠른 자동로그인을 해봅시다.

준비물은 로그인이 가능한 환경입니다...

서버와 로그인 api, 유저 데이터가 존재함을 바탕으로 SharedPreference 사용 방법만을 적었습니다.

java 언어를 기반으로 작성되었습니다.

 


0. SharedPreferences 간단 설명

 

안드로이드에서 사용 가능한 데이터베이스 관리 시스템(DBMS) 중 하나입니다. 

key - value 형태로 관리가 가능해서 간단한 데이터를 저장할 때 주로 쓰입니다. 전 자동로그인 할 때 가장 자주  사용하고 있습니다. 

 

더 자세한 내용을 알고싶다면 하단 링크를 참조해주세요.

 

https://developer.android.com/reference/android/content/SharedPreferences

 

SharedPreferences  |  Android Developers

 

developer.android.com

 

핵심 명령어

https://www.tutorialspoint.com/android/android_shared_preferences.htm

 

Android - Shared Preferences

Android - Shared Preferences Android provides many ways of storing data of an application. One of this way is called Shared Preferences. Shared Preferences allow you to save and retrieve data in the form of key,value pair. In order to use shared preference

www.tutorialspoint.com

 

설명 및 사용예제

https://www.geeksforgeeks.org/shared-preferences-in-android-with-examples/

 

Shared Preferences in Android with Example - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

 

 


 

1. SharedPreferences를 위한 클래스 생성

 

SharedPreferences를 손쉽게 사용하도록 도와줄 클래스를 만들어줍니다.

public class SharedPreferencesManager {
    
}

 

그리고 SharedPreferences를 불러오기 위해 매번 사용해야하는 코드를 편리하게 사용할 수 있도록 메소드로 만들어줍니다.

 

private static final String PREFERENCES_NAME = "my_preferences";

public static SharedPreferences getPreferences(Context mContext){
    return mContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
}

 

왜 고작 한줄의 코드를 메소드로 빼두냐면, SharedPreferences는 불러오는 이름에 따라 저장할 수 있는 값이 달라집니다. 키 - 값 형태로 관리를 한다고 했으니, 다른 이름으로 getSharedPreferences 메소드를 사용하면 또 다른 값이 저장이 되겠죠?

따라서 저는 getPreferences라는 메소드로 자동로그인을 할 데이터만 저장할 예정이라 따로 만들었습니다. 

 

그리고 MODE_PRIVATE는 현재 사용하는 앱에서만 접근을 허락하도록 지정해놓은 것입니다. 여기에 관련된 자세한 항목은 상단 링크를 읽어보시면 더 자세히 알 수 있습니다.

 

이걸로 기본 준비는 끝났습니다.

 

 


 

2. 저장, 불러올 데이터 메소드 생성

 

로그인 정보를 저장, 불러오는 메소드를 만들어줍니다.

로그인의 가장 기본적인 데이터 email, password를 예시로 적었습니다.

필요한 정보를 저장해두면 됩니다!

 

public static void setLoginInfo(Context context, String email, String password){
    SharedPreferences prefs = getPreferences(context);
    SharedPreferences.Editor editor = prefs.edit();
    editor.putString("email", email);
    editor.putString("password", password);

    editor.apply();
}

public static Map<String, String> getLoginInfo(Context context){
    SharedPreferences prefs = getPreferences(context);
    Map<String, String> LoginInfo = new HashMap<>();
    String email = prefs.getString("email", "");
    String password = prefs.getString("password", "");
        
    LoginInfo.put("email", email);
    LoginInfo.put("password", password);

    return LoginInfo;
}

 

해당 값이 null일 수 있으므로 defaultValue또한 공백문자로 처리했습니다. 이렇게 해두면 nullPointException 에러를 막을 수 있습니다. 

 

 


 

3. 사용과 활용

 

 

이제 SharedPreference를 어디서든 부를 수 있게 되었습니다.

따라서 사용자가 로그인 화면의 행동을 모두 끝마쳤을때.

즉, 유효한 데이터로 서버와 통신을 마치고 메인 화면으로 넘어갈 때

SharedPreferencesManager.setLoginInfo(this, email ,password);

이렇게 데이터를 저장해줍니다.

 

 

그 후, 한번 유효한 데이터로 로그인을 했던 사용자가 앱을 종료하고 다시 실행했을 때 SharedPreference에서 데이터를 가져옵시다.

Map<String, String> loginInfo = SharedPreferencesManager.getLoginInfo(this);
if (!loginInfo.isEmpty()){
    String email    = loginInfo.get("email");
    String password = loginInfo.get("password");
    }

 

이렇게 데이터를 가져오고 서버에 로그인 리퀘스트를 해주면 자동로그인이 완성됩니다.

만약 로그인 데이터가 잘못되었다면 로그인화면으로 넘겨야겠죠!

 

 

+ 이 외에도 아이디만 저장하기 기능도 SharedPreference를 활용할 수 있습니다. 보통 로그인 화면에서 체크박스로 확인하니, 로그인 할 때 해당 체크박스를 bool로 저장해두면 됩니다.

 


4. 삭제

 

가장 중요한부분!!!

바로 데이터 삭제입니다. 로그아웃을 했는데 다시 로그인이 되면 큰일나므로...

 

로그아웃, 회원탈퇴 시 꼭! 반드시!! sharedPreference를 삭제해야합니다.

삭제 코드는 다음과 같습니다.

 

public static void clearPreferences(Context context){
    SharedPreferences prefs = getPreferences(context);
    SharedPreferences.Editor editor = prefs.edit();
    editor.clear();
    editor.apply();
}

 

이제 로그아웃시 해당 메소드를 호출하면 됩니다.

 


 

SharedPreferences 전문입니다.

 

public class SharedPreferencesManager {

    private static final String PREFERENCES_NAME = "my_preferences";

    public static SharedPreferences getPreferences(Context mContext){
        return mContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
    }
    
    public static void clearPreferences(Context context){
        SharedPreferences prefs = getPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.clear();
        editor.apply();
    }

    public static void setLoginInfo(Context context, String email, String password){
        SharedPreferences prefs = getPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString("email", email);
        editor.putString("password", password);

        editor.apply();
    }

    public static Map<String, String> getLoginInfo(Context context){
        SharedPreferences prefs = getPreferences(context);
        Map<String, String> LoginInfo = new HashMap<>();
        String email = prefs.getString("email", "");
        String password = prefs.getString("password", "");
        
        LoginInfo.put("email", email);
        LoginInfo.put("password", password);

        return LoginInfo;
    }
    
}

 

 

+ apply와 commit의 차이점!

commit()은 동기, apply()는 비동기 처리 됩니다.

안녕하세요.

안드로이드 스튜디오 java언어로 QR코드 스캐너를 만들 일이 있었는데 제대로 정리를 하기 위해 글을 써봅니다.

 

1. 준비

 

저는 ml kit의 바코드 스캐닝을 받아와서 써야하기 때문에 앱 모듈의 그레이들에 필요한 요소들을 추가해줍니다.

 

디버그용과 릴리즈용, 출시된 앱에 따라 추가해야하는 코드가 다르니 꼭 확인 후 추가해주세요.

 

https://developers.google.com/ml-kit/vision/barcode-scanning/android

 

Scan Barcodes with ML Kit on Android  |  Google Developers

Scan Barcodes with ML Kit on Android You can use ML Kit to recognize and decode barcodes. There are two ways to integrate barcode scanning: by bundling the model as part of your app, or by using an unbundled model that depends on Google Play Services. If y

developers.google.com

 

그리고 jetpack의 카메라X를 쓸 예정이라 그것도 들고와서 추가해줍시다.

 

https://developer.android.com/jetpack/androidx/releases/camera

 

CameraX  |  Android 개발자  |  Android Developers

CameraX CameraX가 Jetpack에 추가되어 앱에 카메라 기능을 더 쉽게 추가할 수 있습니다. 라이브러리는 다양한 호환성 수정사항과 해결 방법을 제공하여 많은 기기에서 개발자 환경을 일관되게 유지하

developer.android.com

 

하지만 !!!!!!

21.12.04 날짜를 기준으로 공식 문서에 있는 최신 카메라X를 적용시 sdk 31버전과 충돌이 있는 것 같아요.

그래서 다음과 같은 에러가 발생합니다.

 

java.lang.NoSuchMethodError: No static method getOrCreateInstance

 

이럴 경우 카메라X의 이전 버전을 들고와서 적용해줍니다.

 

def camerax_version = "1.0.1"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha27"

 

추가가 끝났다면 카메라 사용을 위한 퍼미션 체크를 해주세요.

카메라 퍼미션은 다루지 않겠습니다.

 

2. xml

카메라를 보여줄 화면을 만들어줍니다.

카메라X의 프리뷰를 xml에 예쁘게 넣어봅시다.

 

<androidx.camera.view.PreviewView
    android:id="@+id/camerax_preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:importantForAccessibility="no"
    />

 

 

3. 카메라 뷰 바인딩

 

카메라X 세팅을 해주고 이미지를 분석할 수 있는 준비를 해줍시다.

이미지를 분석하기 위해서는 executor와 analyzer가 필요합니다. 

 

imageAnalysis.setAnalyzer(cameraExecutor, myImageAnalyzer);

(분석시키기 위해 cameraExecutor와 analyzer를 넣어줘야하는 모습)

 

 

 

executor는 ExecutorService 외에도 터프하게

 

Executor executor = Executors.newSingleThreadExecutor(); 

 

초기화 해서 사용 가능합니다. 저는 ExecutorService를 사용했습니다.

 

public class MainActivity extends AppCompatActivity {

    private PreviewView mPreviewView;
    private ListenableFuture cameraProviderFuture;
    private ExecutorService cameraExecutor;

    private MyImageAnalyzer myImageAnalyzer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();
    }

    private void init(){
        mPreviewView = findViewById(R.id.camerax_preview);

        cameraExecutor = Executors.newSingleThreadExecutor();
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        myImageAnalyzer = new MyImageAnalyzer(this.getSupportFragmentManager());

        cameraProviderFuture.addListener(new Runnable() {
            @Override
            public void run() {
                try {
                    ProcessCameraProvider processCameraProvider = (ProcessCameraProvider) cameraProviderFuture.get();
                    bindPreview(processCameraProvider);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, ContextCompat.getMainExecutor(this));


    }

    private void bindPreview(ProcessCameraProvider processCameraProvider) {
        Preview preview = new Preview.Builder().build();
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        ImageCapture imageCapture =new ImageCapture.Builder().build();
        ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                .setTargetRotation(Surface.ROTATION_270)
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build();
        preview.setSurfaceProvider(mPreviewView.getSurfaceProvider());

        imageAnalysis.setAnalyzer(cameraExecutor, myImageAnalyzer);

        processCameraProvider.unbindAll();
        processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalysis);

    }

 

 

이제 카메라 준비가 끝났습니다.

카메라로 가져온 이미지에서 정보를 가져오는 스캐닝 작업을 해주기 전에!!

 

 

내부 클래스로 analyzer를 만들어줍니다.

공식에서 적어준걸 가져옵시다.

 

https://developers.google.com/ml-kit/vision/barcode-scanning/android#java

 

Scan Barcodes with ML Kit on Android  |  Google Developers

Scan Barcodes with ML Kit on Android You can use ML Kit to recognize and decode barcodes. There are two ways to integrate barcode scanning: by bundling the model as part of your app, or by using an unbundled model that depends on Google Play Services. If y

developers.google.com

 

public class MyImageAnalyzer implements ImageAnalysis.Analyzer{
    private FragmentManager fragmentManager;

    public MyImageAnalyzer(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
    }

    @Override
    public void analyze(@NonNull ImageProxy image) {
        scanBarcode(image);
    }
}

 

 

4. 바코드 스캐닝

 

analyzer 에서 던져주는 ImageProxy를 분석하는 코드입니다.

 

private void scanBarcode(ImageProxy image) {

    //input image
    @SuppressLint("UnsafeOptInUsageError") Image image1 = image.getImage();
    InputImage inputImage = InputImage.fromMediaImage(image1, image.getImageInfo().getRotationDegrees());

    BarcodeScannerOptions options =
            new BarcodeScannerOptions.Builder()
                    .setBarcodeFormats(
                            Barcode.FORMAT_QR_CODE,
                            Barcode.FORMAT_AZTEC)
                    .build();

    //Get an instance of BarcodeScanner
    BarcodeScanner scanner = BarcodeScanning.getClient(options);

    //process the image
    Task<List<Barcode>> result = scanner.process(inputImage)
            .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() {
                @Override
                public void onSuccess(List<Barcode> barcodes) {
                    readerBarcodeData(barcodes);
                    Log.d("cameraSuccess::", barcodes.toString());
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Task failed with an exception
                    // ...
                    Log.d("cameraFail::", e.toString());
                }
            })
            .addOnCompleteListener(new OnCompleteListener<List<Barcode>>() {
                @Override
                public void onComplete(@NonNull Task<List<Barcode>> task) {
                    image.close();
                }
            });
}

 

BarcodeScannerOptions 에서 옵션을 다르게 선택하면 QR코드가 아니라 바코드를 읽어낼 수 있습니다.

지금은 QR코드만 스캔할 수 있도록 옵션을 설정해두었습니다.

 

이렇게 성공적으로 바코드 스캔까지 마쳤으면 바코드가 담고있는 정보를 가져와 정제를 해줍니다.

 

//get information barcode
private void readerBarcodeData(List<Barcode> barcodes) {
    for (Barcode barcode: barcodes) {
        Rect bounds = barcode.getBoundingBox();
        Point[] corners = barcode.getCornerPoints();

        String rawValue = barcode.getRawValue();

        int valueType = barcode.getValueType();

        // See API reference for complete list of supported types
        switch (valueType) {
            case Barcode.TYPE_WIFI:
                Toast.makeText(this, "wifi", Toast.LENGTH_SHORT).show();

                String ssid = barcode.getWifi().getSsid();
                String password = barcode.getWifi().getPassword();
                int type = barcode.getWifi().getEncryptionType();

                cameraExecutor.shutdownNow();

                break;
            case Barcode.TYPE_URL:
                Toast.makeText(this, "url", Toast.LENGTH_SHORT).show();
                String title = barcode.getUrl().getTitle();
                String url = barcode.getUrl().getUrl();

                cameraExecutor.shutdownNow();

                break;
        }
    }
}

 

바코드가 담고있는 정보의 타입에 따라 어떻게 다룰것인지 나눠줍니다.

url을 받아왔으면 intent로 넘겨줄 수 있겠네요!

 

 

이렇게 끝!

일 줄 알았겠지만 현재 사용중인 액티비티가 꺼질때 백그라운드에서 카메라가 돌지 않도록 꺼줍시다.

꺼주지 않으면... 혼나요.

 

private void closeCamera(){
    if (cameraProviderFuture != null && cameraExecutor != null){
        cameraProviderFuture.cancel(true);
        cameraProviderFuture = null;
        cameraExecutor.shutdown();
        cameraExecutor = null;
    }
}

 

저는 그냥 null을 박아버렸습니다.

사실 더 좋은 방법이 있지 않을까 싶은데 없애주는 게 마음이 편해요.

카메라 꺼주는 메소드를 만들어서

 

@Override
protected void onPause() {
    super.onPause();
    closeCamera();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    closeCamera();
}

 

이렇게 붙여줍니다.

onPause에서 카메라를 없앴으니 onResume에서는 다시 켜줘야겠죠!!

 

코드 전문은 깃헙을 참조해주세요.

 

https://github.com/jmnl225/QRcodeScanner

 

GitHub - jmnl225/QRcodeScanner

Contribute to jmnl225/QRcodeScanner development by creating an account on GitHub.

github.com

 

+ Recent posts