Um novo canal de comércio, o de pagamentos móveis (m-payment)
Empresas como a MTV, a Fox Entertainment, a NBC, a LOreal e a Nike já aceitam pagamentos via mobile PenPal. As operações são feitas via portal WAP da PenPal desenvolvido para mobile payment. O Banco do Brasil e o Google já está entrando na onda.
Exemplo oficial da API
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.payment.TransactionListener;
import javax.microedition.payment.TransactionModule;
import javax.microedition.payment.TransactionRecord;
import javax.microedition.payment.TransactionModuleException;
public class MyGame extends MIDlet implements TransactionListener, CommandListener {
private TransactionModule transModulo;
private int aNivel = 0;
private int nbNivel = 0;
private int MAX_NIVEL = 3;
private Display tela;
private Command sair;
public MyGame(){
tela = Display.getDisplay(this);
Form formMain = new Form("GamePay");
sair = new Command("Exit", Command.EXIT, 1);
formMain.addCommand(sair);
formMain.setCommandListener(this);
tela.setCurrent(formMain);
try {
transModulo = new TransactionModule(this);
}
catch(TransactionModuleException e) {
/* O módulo do pagamento indica que recusou uma conexão de TransactionModule.
Possíveis motivos: os dados da provisão estão errados ou incompletos ou que há conexões excessivas ligadas a esse módulo de pagamento */
e.toString();
}
catch(Exception e) { }
try {
transModulo.setListener(this);
} catch(Exception e) { }
}
public void startApp(){
while (nbNivel <= MAX_NIVEL) {
// pagamento (payment) obrigatório p/ o nível
try {
transModulo.process(aNivel, "Prox Nível", "Libera o acesso ao nível seguinte.");
synchronized(this) {
try {
wait(); // esperar até que a rechamada seja feita
}
catch (InterruptedException ie) { }
}
}
catch (Exception e) { }
// início do nível
Form formLevel = new Form("Nivel " + nbNivel);
tela.setCurrent(formLevel);
try {
Thread.sleep(5000);
}
catch (InterruptedException e1) {
el.getMessage()
}
// fim do nível
nbNivel++;
}
}
public void processed(TransactionRecord record){
switch(record.getState()) {
case TransactionRecord.TRANSACTION_SUCCESSFUL:
// transação de pagamento bem sucedida
break;
case TransactionRecord.TRANSACTION_REJECTED:
// transação de pagamento mal sucedida, deve-se pagar para jogar
break;
case TransactionRecord.TRANSACTION_FAILED:
default:
// problemas técnicos - tente de novo
break;
}
synchronized(this) {
notify(); // notifica emquanto espera thread
}
}
protected void pauseApp() { }
protected void destroyApp(boolean arg0) { }
public void commandAction(Command command, Displayable telaable){
if (command == sair) {
destroyApp(true);
notifyDestroyed();
}
}
}
Pequeno exemplo 2
import javax.microedition.payment.*;
...
public class MyGame extends MIDlet implements TransactionListener, CommandListener {
private TransactionModule myTransactionModule;
public GamePay2(){
...
try {
myTransactionModule = new TransactionModule(this);
}
catch(TransactionModuleException e) { }
try {
myTransactionModule.setListener(this);
}
catch(Exception e) { }
}
public void startApp(){
...
try {
myTransactionModule.process(caracteristicasID, ?Titulo de Caracteristicas", "Descrição das Caracteristicas");
synchronized(this) {
try {
wait(); // espere enquanto a rechamada é realizada
}
catch (InterruptedException ie) { }
}
}
catch (Exception e) { }
...
}
public void processed(TransactionRecord myPaytRecord){
switch(myPayRecord.getState()) {
case TransactionRecord.TRANSACTION_SUCCESSFUL:
// transação de pagamento bem sucedida
break;
case TransactionRecord.TRANSACTION_REJECTED:
// transação de pagamento rejeitado
break;
case TransactionRecord.TRANSACTION_FAILED:
default:
// problemas técnicos - tente novamente
break;
}
...
}
}
Mais info em: https://sdlc5a.sun.com/ECom/EComActionServlet;jsessionid=EA44F16E59366B5928347F1515619CFB
Site oficial -> http://jcp.org/en/jsr/detail?id=229
Arquivo JAD:
Pay-Version: 1.0
Pay-Adapters: PPSMS, X-TEST
MIDlet-Permissions: javax.microedition.payment.process.jpp
MIDlet-Certificate-<n>-<m>: <base64 encoding of a certificate>
MIDlet-Jar-RSA-SHA1: <base64 encoded Jar signature>
Arquivo JAR-Manifest:
Pay-Version: 1.0
Pay-Update-Stamp: 2004-11-15 02:00+01:00
Pay-Providers: SMS1, Test1Card
Pay-Update-URL: http://<update-site>/thisgame.manifest.jpp
Pay-Cache: no
Pay-Feature-0: 0
Pay-Feature-1: 0
Pay-Feature-2: 1
Pay-SMS1-Info: PPSMS, EUR, 928, 99
Pay-SMS1-Tag-0: 1.20, 9990000, 0x0cba98765400
Pay-SMS1-Tag-1: 2.50, 9990000, 0x0cba98765401, 2
Pay-Test1Card-Info: X-TEST8, EUR, c4d21, soap://<soap-site-1>/
Pay-Test1Card-Tag-0: 1.21
Pay-Test1Card-Tag-1: 2.46
Um exemplo complexo do arquivo JAR-Manifest:
Pay-Version: 1.0
Pay-Update-Stamp: 2004-11-15 02:00+01:00
Pay-Providers: SONERA, RADIOG, DNSDNA
Pay-Update-URL: http://<update-site>/thisgame.manifest.jpp
Pay-Cache: no
Pay-Feature-0: 0
Pay-Feature-1: 0
Pay-Feature-2: 1
If user?s operator is ?Sonera?, MNC=928, MCC=99
Pay-SONERA-Info: PPSMS, EUR, 928, 99
Pay-SONERA-Tag-0: 1.20, 9990000, 0x0cba98765400
Pay-SONERA-Tag-1: 2.50, 9990000, 0x0cba98765401, 2
If user?s operator is ?RadioG?, MNC=747, MCC=88
Pay-RADIOG-Info: PPSMS, EUR, 747, 88
Pay-RADIOG-Tag-0: 1.21, 34501, 0xf9b500
Pay-RADIOG-Tag-1: 2.49, 34502, 0xf9b501, 3
If user?s operator is ?DNSDNA?, MNC=380, MCC=77
Pay-DNSDNA-Info: PPSMS, EUR, 380, 77
Pay-DNSDNA-Tag-0: 1.41, 19076501, _DNS
Pay-DNSDNA-Tag-1: 1.99, 19023202, _DNS
Uma alternativa p/ quem precisa realizar um pagamento mas não possui a JSR 229 no aparelho, pode usar conexões HTTPS e post
import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
public class SslTest extends MIDlet implements CommandListener {
private final String merchant="4181607";
private final String amount="19095";
private final String currency="208";
private final String orderid ="991002b";
private final String accepturl ="https://payment.architrade.com/cgissl/relay.cgi/http://www.java4mobile/dibs/godkendt.jsp";
private final String declineurl ="https://payment.architrade.com/cgissl/relay.cgi/http://www.java4mobile/dibs/afvist.jsp";
private final String test="foo";
private String cardno;
private String expmon;
private String expyear;
private String cvc;
private String url = "https://payment.architrade.com/cgi-ssl/auth.cgi";
private String post;
private String urlTotal;
private Command exitCommand = new Command("Exit", Command.EXIT, 2);
private Command getCommand = new Command("Pay", Command.SCREEN, 1);
private Form form;
private TextField txtCardno = new TextField("Card no:", null , 16, TextField.NUMERIC);
private TextField txtExpmon = new TextField("Expmon", null, 2, TextField.NUMERIC);
private TextField txtExpyear = new TextField("Expyear", null , 2, TextField.NUMERIC);
private TextField txtCvc = new TextField("Cvc", null, 3, TextField.NUMERIC);
private Display display;
public SslTest() { }
public void startApp() {
if (display == null)
display = Display.getDisplay(this);
form = new Form("Payment");
form.append(txtCardno);
form.append(txtExpmon);
form.append(txtExpyear);
form.append(txtCvc);
form.addCommand(exitCommand);
form.addCommand(getCommand);
form.setCommandListener(this);
display.setCurrent(form);
}
public void commandAction(Command c, Displayable d) {
if (c == exitCommand) {
notifyDestroyed();
}
else if (c == getCommand) {
cardno=txtCardno.getString();
expmon=txtExpmon.getString();
expyear=txtExpyear.getString();
cvc=txtCvc.getString();
post = "?merchant="+merchant+"&amount="+amount+"¤cy="+currency+"&orderid="+orderid+ "&accepturl="+accepturl+"&declineurl="+declineurl+"&cardno="+cardno+"&expmon="+expmon+ "&expyear="+expyear+"&cvc="+cvc+"&test="+test;
StringBuffer b = new StringBuffer();
HttpsConnection con = null;
InputStream is = null;
OutputStream os = null;
urlTotal = url+post;
try {
int len = 0;
int ch = 0;
con = (HttpsConnection)Connector.open(urlTotal);
con.setRequestMethod(HttpsConnection.POST);
/*
byte[] data = post.getBytes();
con.setRequestProperty("Content-Length",
Integer.toString(data.length));
os = con.openOutputStream();
os.write( data );
os.close();
*/
System.out.println(Integer.toString(con.getResponseCode()));
is = con.openInputStream();
len = (int) con.getLength();
if (len != -1) {
for(int i=0; i<len; i++) {
if((ch = is.read()) != -1) {
b.append((char) ch);
}
}
}
else {
while((ch = is.read()) != -1) {
len = is.available();
b.append((char) ch);
}
}
System.out.println("Response: " +b.toString());
Alert a = new Alert("Trans results:", b.toString(), null, null);
a.setTimeout(Alert.FOREVER);
display.setCurrent(a);
}
catch (Exception e) {
e.printStackTrace();
String s = e.toString();
If(s != null) {
Alert aa = new Alert("Error in connection:", s, null, null);
aa.setTimeout(Alert.FOREVER);
display.setCurrent(aa);
}
}
finally {
if (is != null) {
try {
is.close();
}
catch (Exception ce) { }
}
if (c != null) {
try {
con.close();
}
catch (Exception ce) { }
}
}
}
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) { }
}
Mais info em: Analysis of J2ME for developing Mobile Payment Systems -> www.microjava.com/articles/techtalk/mpayment
P/ testar se a API é suportada pelo aparelho
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;
public class JSRTest extends MIDlet implements Runnable,CommandListener{
Form form;
Thread thread;
Command c=new Command("Exit",Command.EXIT,0);
public JSRTest()
{
Display.getDisplay(this).setCurrent(form=new Form("JSR Test"));
form.addCommand(c);
form.setCommandListener(this);
(thread=new Thread(this)).start();
}
protected void destroyApp(boolean u){
super.notifyDestroyed();
}
protected void pauseApp() {
}
protected void startApp(){
}
public void run() {
checkJSR("MIDP2.0","javax.microedition.lcdui.game.GameCanvas");
checkJSR("CLDC1.1","java.lang.Float");
checkJSR("MMAPI","javax.microedition.media.Player");
checkJSR("WMAPI","javax.wireless.messaging.Message");
checkJSR("JSR75","javax.microedition.io.file.FileConnection");
checkJSR("JSR082","javax.bluetooth.UUID");
checkJSR("JSR179","javax.microedition.location.Location");
checkJSR("JSR180","javax.microedition.sip.SipConnection");
checkJSR("JSR184","javax.microedition.m3g.Mesh");
checkJSR("JSR211","javax.microedition.content.Registry");
checkJSR("JSR226","javax.microedition.m2g.SVGImage");
checkJSR("JSR229","javax.microedition.payment.TransactionRecord");
checkJSR("JSR234","javax.microedition.amms.Module");
checkJSR("JSR238","javax.microedition.global.Formatter");
checkJSR("JSR239","javax.microedition.khronos.egl.EGL");
}
private void checkJSR(String jsr,String className)
{
try {
Class.forName(className);
form.append(jsr+" Supproted\n");
} catch (ClassNotFoundException e) {
form.append(jsr+" Not Supproted\n");
}
}
public void commandAction(Command cmd, Displayable disp) {
this.destroyApp(false);
}
}