Today's

길을 나서지 않으면 그 길에서 만날 수 있는 사람을 만날 수 없다

모바일 앱(안드로이드)

안드로이드 앱 만들기 문자 한번에 보내기는 어떻게 ?

Billcorea 2021. 9. 6. 13:46
반응형

아무래도 휴대폰에 앱을 개발하는 일이다 보니, 문자 전송 같은 기본 기능을 이용하는 앱을 개발하는 일이 많기는 하다.  요새는 카카오톡등을 이용하거나, FCM 등을 이용해서 알림을 보내는 기능등을 구현해 보지만, 예전 방식 처럼 SMS 을 전송해 보는 것도 오랜만 이기는 하다.

구글이 계정 정책등으로 인해 앱을 등록할 때 기본앱으로 사용할 수 없는 SMS 앱은 등록에 무리가 있다. 그래서 그냥 개인적으로 사용하기 위해서 기본앱 기능은 아니지만, 필요에 의한 문자 전송을 구현하는 앱을 만들어 볼 까 싶다.

먼저 앱을 구동하기 위해서는 Manifest 파일에 권한 설정을 등록해 준다. 

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

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

    <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/Theme.SMSSend0823">
        
        ......
        
    </application>

</manifest>

SMS 발송 권한을 설정했으니, 앱을 실행하면서 실제 동작이 발생 하기 전에 사용자에게 권한을 획득 하는 코드를 activity 에 넣어 보자.

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;

import com.example.smssend0823.Database.DBHandler;
import com.example.smssend0823.Database.MsgTargetBean;
import com.example.smssend0823.Database.SendMessageAdapter;
import com.example.smssend0823.Database.SendMessageBean;
import com.example.smssend0823.Utils.OnBackPressedListener;
import com.example.smssend0823.databinding.FragmentMsgselectBinding;

import java.util.ArrayList;

public class MsgSelectFragment extends Fragment implements OnBackPressedListener {

    private static final String TAG = "MsgSelectFragment";
    private FragmentMsgselectBinding binding;
    ArrayList<SendMessageBean> beans;
    SendMessageAdapter adapter;
    DBHandler dbHandler ;
    String phoneNo ;
    String message ;
    private static final int PERMISSION_RQST_SEND = 101;

    public static Fragment newInstance() {
        MsgSelectFragment fragment = new MsgSelectFragment();
        return fragment;
    }

    @Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {

        binding = FragmentMsgselectBinding.inflate(inflater, container, false);
        return binding.getRoot();

    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        beans = new ArrayList<>();
        doDisplaySendMessage();
        binding.listSendMessage.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                int iCnt = 0 ;
                for(int i=0; i < beans.size() ;  i++) {
                    if (beans.get(i).isSelectedMsg()) iCnt++;
                }
                if (iCnt > 0) {
                    beans.get(position).setSelectedMsg(false);
                    adapter.notifyDataSetChanged(beans);
                    Toast.makeText(getContext(), iCnt +"개 이상 선택할 수 없습니다.", Toast.LENGTH_SHORT).show();
                    return;
                }
                beans.get(position).setSelectedMsg(!beans.get(position).isSelectedMsg());
                adapter.notifyDataSetChanged(beans);
            }
        });

        binding.btnSendMessage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = 0 ; int iCnt = 0 ;
                for(int i=0; i < beans.size() ;  i++) {
                    if (beans.get(i).isSelectedMsg()) {
                        position = i;
                        iCnt++;
                        break;
                    };
                }
                if (iCnt == 0) {
                    Toast.makeText(getContext(), "전송할 메시지를 선택하세요.", Toast.LENGTH_SHORT).show();
                    return;
                }
                message = beans.get(position).getSendMessage() ;
                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                builder.setTitle("메시지 전송")
                        .setMessage("[" + beans.get(position).getSendMessage() + "] 로 전송할까요?")
                        .setPositiveButton("확인", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dbHandler = DBHandler.open(getContext());
                                Cursor rs = dbHandler.selectAll();
                                while(rs.moveToNext()) {
                                    MsgTargetBean msgTargetBean = new MsgTargetBean();
                                    msgTargetBean.setId(rs.getInt(rs.getColumnIndex("_id")));
                                    msgTargetBean.setSendSeqNo(rs.getString(rs.getColumnIndex("sendSeqNo")));
                                    msgTargetBean.setReceivePhoneNum(rs.getString(rs.getColumnIndex("receivePhoneNum")));
                                    msgTargetBean.setSendMessage(rs.getString(rs.getColumnIndex("sendMessage")));
                                    msgTargetBean.setSendTy(rs.getString(rs.getColumnIndex("sendTy")));
                                    if("S".equals(msgTargetBean.getSendTy())) {
                                        phoneNo = msgTargetBean.getReceivePhoneNum();
                                        if (sendSMSMessage()) {
                                            msgTargetBean.setSendTy("Y");
                                            msgTargetBean.setSendMessage(message);
                                            dbHandler.update(msgTargetBean);
                                        }
                                    }
                                }
                                dbHandler.close();
                            }
                        })
                        .setNegativeButton("취소", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });
    }

    private void doDisplaySendMessage() {
        beans.clear();
        dbHandler = DBHandler.open(getContext());
        Cursor rs = dbHandler.selectMsgAll();
        while (rs.moveToNext()) {
            SendMessageBean bean = new SendMessageBean();
            bean.setSendMessage(rs.getString(rs.getColumnIndex("messageString")));
            beans.add(bean);
        }
        adapter = new SendMessageAdapter(beans, getContext());
        adapter.notifyDataSetChanged(beans);
        binding.listSendMessage.setAdapter(adapter);
    }

    protected boolean sendSMSMessage() {
        if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(getContext(), "SMS 전송 권한에 대한 허가가 필요합니다.", Toast.LENGTH_SHORT).show();
            if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),Manifest.permission.SEND_SMS)) {
                Log.e(TAG, "shouldShowRequestPermissionRationale");
            }
            else { ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.SEND_SMS}, PERMISSION_RQST_SEND);
                Log.e(TAG, "requestPermissions");
            }
        } else {
            SmsManager smsManager = SmsManager.getDefault();
            smsManager.sendTextMessage(phoneNo, null, message, null, null);
            Toast.makeText(getContext(), "메시지가 전송 되었습니다.",Toast.LENGTH_LONG).show();
            return true ;
        }
        return false;
    }
    //Now once the permission is there or not would be checked
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_RQST_SEND: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                } else {Toast.makeText(getContext(), "SMS 발송이 되지 않았습니다. 잠시 뒤에 다시 시도 하세요.", Toast.LENGTH_LONG).show();
                    return;
                }
            }
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    @Override
    public void onBackPressed() {
        getParentFragmentManager().beginTransaction()
                .replace(R.id.container, MsgSendListFragment.newInstance())
                .commitNow();
    }
}

 

source code 의 예시와 같이 sendSMSMessage() 함수에는 메시지 발송전에 권한 획득 여부를 확인하고, 권한이 없다면 사용자에게 권한 허가를 요청하는 알림을 띄워 권한을 획득 하게 된다.

반응형

다만, 이런 기능을 앱으로 이용하려면 playstore 에는 등록에 제한이 있으므로 다른 스토어를 이용하여야 한다.

SMS을 보내는 다른 방법은 권한 없이 사용할 수 있는 SMS Retriever API 을 활용하는 방법이 있다고 할 수 있는데, 실제 앱을 개발하다 보면 불편한 사항이 생기게 되어 있다.

https://developers.google.com/identity/sms-retriever/overview

 

SMS Retriever API를 사용한 자동 SMS 확인  |  SMS Verification APIs

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English SMS Retriever API를 사용한 자동 SMS 확인 SMS Retriever API를 사용하면 사용자가 인증 코드를 수동으로 입력 할 필요없이 추가 앱 권

developers.google.com

참고해서 보면 좋을 것 깥다.

 

반응형