๐ŸŒฑ I'mport Android SDK ๐ŸŒฑ

์„ค๋ช…

์•ˆ๋“œ๋กœ์ด๋“œ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ์—์„œ ๊ฒฐ์ œ ๊ฐœ๋ฐœ์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋„์™€์ฃผ๋Š” ์•„์ž„ํฌํŠธ SDK ์ž…๋‹ˆ๋‹ค.

  • CHAI ๊ฐ„ํŽธ๊ฒฐ์ œ๋Š” Native ์—ฐ๋™๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ทธ์™ธ PG ๋“ค์€ WebView ๊ธฐ๋ฐ˜์œผ๋กœ ์—ฐ๋™๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ถ”ํ›„ ์ˆœ์ฐจ์ ์œผ๋กœ ํƒ€ ๊ฐ„ํŽธ๊ฒฐ์ œ๋“ค๋„ ๋„ค์ดํ‹ฐ๋ธŒ ์—ฐ๋™ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.


๐Ÿ”ฅ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

Gradle implementation

project build.gradle

  maven {
    url 'https://jitpack.io'
  }

app build.gradle $SDK-VERSION

  implementation 'com.github.iamport:iamport-android:$SDK-VERSION'

KOTLIN usage

ํ•„์ˆ˜๊ตฌํ˜„ ์‚ฌํ•ญ

  // ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ
  // ์‚ฌ์šฉํ•˜์‹œ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•˜์„ธ์š”
  class BaseApplication : Application() {
    override fun onCreate() {
        ..
        Iamport.create(this)
    }
  }
    
   // DI ๋กœ koin ์„ ์‚ฌ์šฉํ•˜์‹œ๋Š” ๊ฒฝ์šฐ 
   // ์ƒ์„ฑ๋œ koinApplication ์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค
   class BaseApplication : Application() {
    override fun onCreate() {
        ..   
        val koinApp = startKoin { .. }
        Iamport.create(this, koinApp)
    }
    
    // KoinApplication ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ
    Iamport.getKoinApplition() 
}
  // SDK ์ดˆ๊ธฐํ™”
  // activity ์—์„œ ํ˜ธ์ถœ์‹œ : LifecycleOwners must call register before they are STARTED.
  // fragement ์—์„œ ํ˜ธ์ถœ์‹œ : Fragments must call before they are created (i.e. initialization, onAttach(), or onCreate())
  fun onCreate() {
      Iamport.init(this)
      ..
  }

  // SDK ์ข…๋ฃŒ
  // activity ์—์„œ ํ˜ธ์ถœ์‹œ : onDestroy
  // fragement ์—์„œ ํ˜ธ์ถœ์‹œ : onDestroy, onDetach ๋“ฑ
  // ๊ณตํ†ต : ํ™”๋ฉด์„ ๋‚˜๊ฐ€๋Š” ์‹œ์ , ๊บผ์ง€๋Š” ์‹œ์  ๋“ฑ์— ์ถ”๊ฐ€
  fun onDestroy() {
    Iamport.close() 
    ..
  }


  // SDK ์— ๊ฒฐ์ œ ์š”์ฒญํ•  ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ
  val request = IamPortRequest(
      pg = "chai",                                   // PG ์‚ฌ
      pay_method = PayMethod.trans,                 // ๊ฒฐ์ œ์ˆ˜๋‹จ
      name = "์—ฌ๊ธฐ์ฃผ๋ฌธ์ด์š”",                          // ์ฃผ๋ฌธ๋ช…
      merchant_uid = "mid_123456",                // ์ฃผ๋ฌธ๋ฒˆํ˜ธ
      amount = "3000",                           // ๊ฒฐ์ œ๊ธˆ์•ก
      buyer_name = "ํ™๊ธธ๋™"
  )
  

  // ๊ฒฐ์ œ์š”์ฒญ
  Iamport.payment("imp123456", request,
      approveCallback = { /* (Optional) ์ฐจ์ด ์ตœ์ข… ๊ฒฐ์ œ์ „ ์ฝœ๋ฐฑ ํ•จ์ˆ˜. */ },
      paymentResultCallback = { /* ์ตœ์ข… ๊ฒฐ์ œ ํ›„ ์ฝœ๋ฐฑํ•จ์ˆ˜ */ })
      

Optional ๊ตฌํ˜„์‚ฌํ•ญ for CHAI ๊ฒฐ์ œ

  • ์ฐจ์ด ๊ฒฐ์ œ์—์„œ approveCallback ์ด ์žˆ์„ ๋•Œ (์ตœ์ข… ๊ฒฐ์ œ์ „ ์žฌ๊ณ  ํ™•์ธ ๋“ฑ์ด ํ•„์š”ํ•  ๋•Œ)
    ์ฝœ๋ฐฑ ์ „๋‹ฌ ๋ฐ›์€ ํ›„์— chaiPayment ํ•จ์ˆ˜ ํ˜ธ์ถœ
    (ํƒ€์ž„์•„์›ƒ : CONST.CHAI_FINAL_PAYMENT_TIME_OUT_SEC)
  Iamport.chaiPayment(iamPortApprove) // ์žฌ๊ณ  ๋“ฑ ํ™•์ธ ํ›„, ์ฐจ์ด ์ตœ์ข… ๊ฒฐ์ œ ์š”์ฒญ ์‹คํ–‰.
  • ์ฐจ์ด ๊ฒฐ์ œ ํด๋ง ์—ฌ๋ถ€ ํ™•์ธ
  // ์ฐจ์ด ๊ฒฐ์ œ ์ƒํƒœ์ฒดํฌ ํด๋ง ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  Iamport.isPolling()?.observe(this, EventObserver {
      i("์ฐจ์ด ํด๋ง? :: $it")
  })

  // ๋˜๋Š”, ํด๋ง ์ƒํƒœ๋ฅผ ๋ณด๊ณ  ์‹ถ์„๋•Œ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœ
  i("isPolling? ${Iamport.isPollingValue()}")
  • ์ฐจ์ด ๊ฒฐ์ œ ํด๋ง ์ค‘์—๋Š” ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๊ฐ€ ์•Œ๋žŒ์— ๋œจ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
    enableService = true ๋ผ๋ฉด, ํด๋ง์ค‘ ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
    enableFailStopButton = true ๋ผ๋ฉด, ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค์—์„œ ์ค‘์ง€ ๋ฒ„ํŠผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    (ํ•ด๋‹น enableChaiPollingForegroundService(false, false) ๋ฅผ Iamport.payment(๊ฒฐ์ œ ํ•จ์ˆ˜) ์ „์— ํ˜ธ์ถœํ•ด์ฃผ์‹œ๋ฉด ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค)
  Iamport.enableChaiPollingForegroundService(enableService = true, enableFailStopButton = true)
  • ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ์•Œ๋žŒ ๋ฐ ์ค‘์ง€ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๋™์ž‘์„
    ์•„๋ž˜ ๊ฐ’์˜ ๋ธŒ๋กœ๋“œ ์บ์ŠคํŠธ ๋ฆฌ์‹œ๋ฒ„๋ฅผ ํ†ตํ•ด ์บ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ˜ํ”Œ์•ฑ์˜ ์˜ˆ์‹œ MerchantReceiver.kt

  const val BROADCAST_FOREGROUND_SERVICE = "com.iamport.sdk.broadcast.fgservice"
  const val BROADCAST_FOREGROUND_SERVICE_STOP = "com.iamport.sdk.broadcast.fgservice.stop"
  • (ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ์ง์ ‘ ๊ตฌํ˜„์‹œ์—๋Š” enableService = false ๋กœ ์„ค์ •ํ•˜๊ณ ,
    Iamport.isPolling()?.observe ์—์„œ true ์ „๋‹ฌ ๋ฐ›์„ ์‹œ์ ์—, ์ง์ ‘ ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ๋งŒ๋“ค์–ด ๋„์šฐ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.)

์ž๋ฐ” ํ”„๋กœ์ ํŠธ๋Š” ์•„๋ž˜ [ํŽผ์ณ๋ณด๊ธฐ] ๋ฅผ ์ฐธ์กฐํ•ด์ฃผ์„ธ์š”

ํŽผ์ณ๋ณด๊ธฐ

JAVA usage

์ž๋ฐ” ํ”„๋กœ์ ํŠธ์—์„  app build.gradle ์—์„œ kotin-stblib ์ถ”๊ฐ€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค $์ฝ”ํ‹€๋ฆฐ-๋ฒ„์ „

  implementation "org.jetbrains.kotlin:kotlin-stdlib:$์ฝ”ํ‹€๋ฆฐ-๋ฒ„์ „"

ํ•„์ˆ˜๊ตฌํ˜„ ์‚ฌํ•ญ. SDK ์ œ๊ณต api ๋ณ„ ์„ค๋ช…์€ ์œ„์˜ KOTLIN usage ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

  // ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ
  // ์‚ฌ์šฉํ•˜์‹œ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•˜์„ธ์š”
  public class BaseApplication extends Application {
      @Override
      public void onCreate() {
          ..
          Iamport.INSTANCE.create(this, null);
      }
  }

   // DI ๋กœ koin ์„ ์‚ฌ์šฉํ•˜์‹œ๋Š” ๊ฒฝ์šฐ 
   // ์ƒ์„ฑ๋œ koinApplication ์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค
    public class BaseApplication extends Application {
        @Override
        public void onCreate() {
            ..
            KoinApplication koinApp = ..
            Iamport.INSTANCE.create(this, koinApp);
        }
    }
  @Override
  public void onCreate() {
    Iamport.INSTANCE.init(this);
    ..
  }

  @Override
  public void onDeatroy() {
    ..
    Iamport.INSTANCE.close();
  }


  IamPortRequest request
          = IamPortRequest.builder()
          .pg("chai")
          .pay_method(PayMethod.trans)
          .name("์—ฌ๊ธฐ์ฃผ๋ฌธ์ด์š”")
          .merchant_uid("mid_123456")
          .amount("3000")
          .buyer_name("ํ™๊ธธ๋™").build();


  Iamport.INSTANCE.payment("imp123456", request, 
    iamPortApprove -> {
      // (Optional) ์ฐจ์ด ์ตœ์ข… ๊ฒฐ์ œ์ „ ์ฝœ๋ฐฑ ํ•จ์ˆ˜.
      return Unit.INSTANCE;
  }, iamPortResponse -> {
      // ์ตœ์ข… ๊ฒฐ์ œ ํ›„ ์ฝœ๋ฐฑํ•จ์ˆ˜
      return Unit.INSTANCE;
  });

Optional ๊ตฌํ˜„์‚ฌํ•ญ for CHAI ๊ฒฐ์ œ

  • ์ฐจ์ด ๊ฒฐ์ œ์—์„œ approveCallback ์ด ์žˆ์„ ๋•Œ (์ตœ์ข… ๊ฒฐ์ œ์ „ ์žฌ๊ณ  ํ™•์ธ ๋“ฑ์ด ํ•„์š”ํ•  ๋•Œ)
  Iamport.INSTANCE.chaiPayment(iamPortApprove) // ์žฌ๊ณ  ๋“ฑ ํ™•์ธ ํ›„, ์ฐจ์ด ์ตœ์ข… ๊ฒฐ์ œ ์š”์ฒญ ์‹คํ–‰.
  • ์ฐจ์ด ๊ฒฐ์ œ ํด๋ง ์—ฌ๋ถ€ ํ™•์ธ
  Iamport.INSTANCE.isPolling().observe(this, EventObserver -> {
      i("์ฐจ์ด ํด๋ง? :: " + it)
  });

  i("isPolling? " + Iamport.INSTANCE.isPollingValue())
  • ์ฐจ์ด ๊ฒฐ์ œ ํด๋ง ์ค‘์—๋Š” ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๊ฐ€ ์•Œ๋žŒ์— ๋œจ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  Iamport.INSTANCE.enableChaiPollingForegroundService(true, true)
  • ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ์•Œ๋žŒ ๋ฐ ์ค‘์ง€ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๋™์ž‘์„ ์•„๋ž˜ ๊ฐ’์˜ ๋ธŒ๋กœ๋“œ ์บ์ŠคํŠธ ๋ฆฌ์‹œ๋ฒ„๋ฅผ ํ†ตํ•ด ์บ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  const val BROADCAST_FOREGROUND_SERVICE = "com.iamport.sdk.broadcast.fgservice"
  const val BROADCAST_FOREGROUND_SERVICE_STOP = "com.iamport.sdk.broadcast.fgservice.stop"

๐Ÿ’ก ์ƒ˜ํ”Œ์•ฑ

์•ฑ ์†Œ์Šค ํ™•์ธ ๊ฒฝ๋กœ

  1. git clone
  2. Android Studio project open
  3. build app

BaseApplication.kt (SDK ์ƒ์„ฑ)

    override fun onCreate() {
        super.onCreate()
        Iamport.create(this)

        /**
         * DI ๋กœ KOIN ์‚ฌ์šฉ์‹œ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉ
        val koinApp = startKoin {
            logger(AndroidLogger(Level.DEBUG))
            androidContext(this@BaseApplication)
        }
        Iamport.create(this, koinApp)
         */
    }

PaymentFragment.kt (๊ฒฐ์ œ ํ™”๋ฉด)

    // ์ดˆ๊ธฐํ™” ์ฒ˜๋ฆฌ
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Iamport.init(this) // fragment
    }


    // ํฌ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค ์ฒ˜๋ฆฌ์šฉ ๋ธŒ๋กœ๋“œ ์บ์ŠคํŠธ ๋ฆฌ์‹œ๋ฒ„ ๋“ฑ๋ก
    override fun onAttach(context: Context) {
        super.onAttach(context)
        registForegroundServiceReceiver(context)
        ..
    }

 
    // ์ข…๋ฃŒ ์ฒ˜๋ฆฌ
    override fun onDestroy() {
        super.onDestroy()
        Iamport.close()
        ..
    }
    
    
    // ๊ฒฐ์ œ๋ฒ„ํŠผ ํด๋ฆญ
    private fun onClickPayment() {
        ..
        val request = IamPortRequest(
            pg = pg.getPgSting(storeId = ""),           // PG ์‚ฌ
            pay_method = payMethod,                     // ๊ฒฐ์ œ์ˆ˜๋‹จ
            name = paymentName,                         // ์ฃผ๋ฌธ๋ช…
            merchant_uid = merchantUid,                 // ์ฃผ๋ฌธ๋ฒˆํ˜ธ
            amount = amount,                            // ๊ฒฐ์ œ๊ธˆ์•ก
            buyer_name = "๋‚จ๊ถ์•ˆ๋…•"
        )
        
        // ๊ฒฐ์ œํ˜ธ์ถœ
        Iamport.payment(userCode, request,
            approveCallback = { approveCallback(it) },
            paymentResultCallback = { callBackListener.result(it) })
    }
    
    
    // ์ฐจ์ด ๊ฒฐ์ œ์ „ ์ฝœ๋ฐฑ ๋ฐ ์ตœ์ข… ๊ฒฐ์ œ ์š”์ฒญ ์ฒ˜๋ฆฌ
    private fun approveCallback(iamPortApprove: IamPortApprove) {
        val secUnit = 1000L
        val sec = 1
        GlobalScope.launch {
            delay(sec * secUnit) // sec ์ดˆ๊ฐ„ ์žฌ๊ณ ํ™•์ธ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค
            Iamport.chaiPayment(iamPortApprove) // TODO: ์ƒํƒœ ํ™•์ธ ํ›„ SDK ์— ์ตœ์ข…๊ฒฐ์ œ ์š”์ฒญ
        }
    }
    
    
    // fragment ์—์„œ ๋ช…์‹œ์ ์ธ ์ข…๋ฃŒํ•  ๋•Œ ์ฒ˜๋ฆฌ Iamport.close()
    private val backPressCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            Builder(view?.context)
                .setPositiveButton(android.R.string.ok) { _, _ ->
                    Iamport.close() // TODO ๋ช…์‹œ์ ์ธ SDK ์ข…๋ฃŒ
                    requireActivity().finish()
                }
               ..
        }
    }