18 enero 2018

Notificaciones y diálogos con AppleScript y Omnis Studio 8.1


En esta entrada del blog, quisiera exponer un pequeño ejemplo sobre cómo enviar notificaciones y diálogos al sistema macos, las notificaciones pueden resultar muy útiles, pues permiten enviar mensajes al usuario si esperar a que sean aceptados por éste, por otra parte, los diálogos del sistema mantendrá en suspenso la ejecución de Omnis hasta la aceptación del mismo por parte del usuario, pero salva las limitaciones en cuanto a longitud del texto a mostrar en el mismo.

A continuación un ejemplo de cada caso:

Método: $notificacion

Begin text block
Text: {display notification "Una notificación: Hola"}
End text block
Get text block lScript
Do $runapplescript(lScript;lResultado;lError)

Método: $dialogo

Begin text block
Text: {display dialog "Un texto my largo donde quiero explicar todo lo que hace éste programa, un texto my largo donde quiero explicar todo lo que hace éste programa, un texto my largo donde quiero explicar todo lo que hace éste programa,un texto my largo donde quiero explicar todo lo que hace éste programa, un texto my largo donde quiero explicar todo lo que hace éste programa, un texto my largo donde quiero explicar todo lo que hace éste programa, un texto my largo donde quiero explicar todo lo que hace éste programa, un texto my largo donde quiero explicar todo lo que hace éste programa." buttons {"Aceptar"} default button "Aceptar"}
End text block
Get text block lScript
Do $runapplescript(lScript;lResultado;lError)

Saludos cordiales a todos los seguidores de éste blog.


24 diciembre 2017

Comunicaciones seguras con Omnis Studio

Otra importante característica de la versión 8 de Omnis Studio, es la eliminación de la dependencias con OpenSSL como único medio para dotar de soporte a comunicaciones seguras. Como ya sabemos Omnis Studio aporta una buen catálogo de comandos Web con los que realizar éste tipo de conexiones, los denominados: FTPConnect, HTTPOpen, TCPConnect, POP3Connect, SMTPSend, etc.

El haberse eliminado las antiguas dependencias con OpenSSL, ahora ya no será necesaria su instalación adicional en aquellas plataformas donde no se incluía de serie, en su lugar, se usa la tecnología, que de forma predeterminada incorpora cada plataforma, de modo que en el caso de Windows se usa 'Secure Channel' (Schannel), en macOS se usa 'Secure Transport' y sólo en caso de Linux, se seguirá usando OpenSSL ya que es su tecnología de seguridad predeterminada.

No obstante, quisiera recordar en éste artículo, los pasos a seguir cuando (al usar versiones anteriores de Omnis Studio) necesitamos instalar OpenSSL en plataformas Windows, para su uso con Omnis Studio.

Primero recordamos cuales son las librerías que dan soporte a éstos comandos y que podremos hallar bajo el directorio de instalación de Omnis Studio, las denominadas:

  • wesecure.dll que añade una capa de funcionalidad entre weshared y OpenSSL
  • weshared.dll que da soporte a los comandos Web

Ahora lo que necesitaremos es incorporar a éste mismo directorio las librerías libeay32.dll y ssleay32.dll, las cuales podremos obtener de forma gratuita en internet, seleccionando la correspondiente a nuestra plataforma, por ejemplo, desde la web de "embarcadero" que nos facilita su instalación en: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/OpenSSL

Por último deberemos asegurarnos de que también este presente la carpeta o directorio, incluido con Omnis Studio denominado "secure". Omnis Studio usa las "Autoridades de Certificación" instaladas en el subdirectorio denominado "cacerts" del directorio "secure". Si usa su propia "Autoridad de Certificación" para auto-firmar certificados, deberá incluirá en ésta misma carpeta, Omnis la usará tras ser reiniciado.





14 diciembre 2017

Android Studio vs Omnis Studio

En éste artículo quiero comparar lo que supone crear una aplicación sencilla para un dispositivo Android, con dos diferentes herramientas para el desarrollo de "App's": Android Studio (exclusiva de la plataforma y gratuita) y Omnis Studio (multi-plataforma y de pago). Queremos que la aplicación sea capaz de crear una base de datos SQLite en el dispositivo, con tres campos: ID, Nombre y Apellido y cuatro botones para iteracción con el usuario: "Buscar", "Insertar", "Actualizar" y "Borrar", su aspecto y código necesarios se muestran a continuación:

Aspecto con Android Studio

Aspecto con Omnis Studio

Para añadir los elementos de la "interface" en ambos casos sólo ha sido necesario arrastrar y soltar componentes desde sus respectivas paletas, pero a la hora de girar el dispositivo, "Android Studio" a requerido programación adicional, mientras que con "Omnis Studio" no ha sido necesario incluir programación alguna.

A continuación indicaremos el código que ha sido necesario escribir en cada caso, empezando por la creación de la BBDD SQLite en el dispositivo:

Creación de la BBDD en Android Studio

public class Estructura_BBDD {

private Estructura_BBDD() {}

        public static final String TABLE_NAME = "datosPersonales";
        public static final String NOMBRE_COLUMNA1 = "id";
        public static final String NOMBRE_COLUMNA2 = "nombre";
        public static final String NOMBRE_COLUMNA3 = "apellido";

    public static final String SQL_CREATE_ENTRIES =
            "CREATE TABLE " + Estructura_BBDD.TABLE_NAME + " (" +
                    Estructura_BBDD.NOMBRE_COLUMNA1 + " INTEGER PRIMARY KEY," +
                    Estructura_BBDD.NOMBRE_COLUMNA2 + " TEXT," +
                    Estructura_BBDD.NOMBRE_COLUMNA3 + " TEXT)";

    public static final String SQL_DELETE_ENTRIES =
            "DROP TABLE IF EXISTS " + Estructura_BBDD.TABLE_NAME;
}

Creación de la BBDD en Omnis Studio

Do $cinst.$sqlobject.$execute('CREATE TABLE Empleados (Id INTEGER UNIQUE, Nombre TEXT, Apellido TEXT)')
      Returns IDcreatetable

Un apunte antes de continuar en cuanto a la programación asociada a cada botón, en el caso de "Andriod Studio" ha sido necesario añadir código adicional para poner los botones en modo "OnClickListener", cosa totalmente innecesaria en "Omnis Studio", salvando ésta diferencia, (no trivial) indicamos el asociado a cada botón:

Botón "Buscar" en Android Studio

botonBuscar.setOnClickListener(new View.OnClickListener() {
   @Override   public void onClick(View v) {
       SQLiteDatabase db = helper.getReadableDatabase();
       String[] projection = {
               Estructura_BBDD.NOMBRE_COLUMNA2,
               Estructura_BBDD.NOMBRE_COLUMNA3       };

       String selection = Estructura_BBDD.NOMBRE_COLUMNA1 + " = ?";
       String[] selectionArgs = { textoId.getText().toString() };

       try {
           Cursor c = db.query(
                   Estructura_BBDD.TABLE_NAME,         
                   projection,                         
                   selection,                          
                   selectionArgs,                      
                   null,                               
                   null,                               
                   null                                
           );

           c.moveToFirst();
           textoNombre.setText(c.getString(0));
           textoApellido.setText(c.getString(1));

       }catch (Exception e){
           Toast.makeText(getApplicationContext(),"No se han encontrado registros.", Toast.LENGTH_LONG).show();
       }
   }
});

Botón "Buscar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$selectfetch("Select * from Empleados where Id = @[i_ID]";lRow;kFetchAll) 
              Returns IDselectfetch

Botón "Insertar" en Android Studio

botonInsertar.setOnClickListener(new View.OnClickListener() {
    @Override    public void onClick(View v) {
        SQLiteDatabase db = helper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(Estructura_BBDD.NOMBRE_COLUMNA1, textoId.getText().toString());
        values.put(Estructura_BBDD.NOMBRE_COLUMNA2, textoNombre.getText().toString());
        values.put(Estructura_BBDD.NOMBRE_COLUMNA3, textoApellido.getText().toString());

        long newRowId = db.insert(Estructura_BBDD.TABLE_NAME, null, values);
        Toast.makeText(getApplicationContext(),"Insertado ID: " + newRowId, Toast.LENGTH_LONG).show();
    }
});

Botón "Insertar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$insert("INSERT INTO Empleados (Id, Nombre, Apellido) VALUES (@[i_ID],@[i_Nombre],@[i_Apellido])";lRow)
             Returns IDinsert

Botón "Actualizar" en Android Studio

botonActualizar.setOnClickListener(new View.OnClickListener() {
    @Override    public void onClick(View v) {

        SQLiteDatabase db = helper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(Estructura_BBDD.NOMBRE_COLUMNA2, textoNombre.getText().toString());
        values.put(Estructura_BBDD.NOMBRE_COLUMNA3, textoApellido.getText().toString());

        String selection = Estructura_BBDD.NOMBRE_COLUMNA1 + " LIKE ?";
        String[] selectionArgs = { textoId.getText().toString() };

        int count = db.update(
                Estructura_BBDD.TABLE_NAME,
                values,
                selection,
                selectionArgs);
        Toast.makeText(getApplicationContext(),"Registro actualizado.", Toast.LENGTH_LONG).show();
    }
});

Botón "Actualizar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$update("UPDATE Empleados SET Nombre=@[i_Nombre], Apellido=@[i_Apellido] where Id = @[i_ID]";lRow;lRow)
              Returns IDupdate

Botón "Borrar" en Android Studio

botonBorrar.setOnClickListener(new View.OnClickListener() {
    @Override    public void onClick(View v) {

        SQLiteDatabase db = helper.getWritableDatabase();
        String selection = Estructura_BBDD.NOMBRE_COLUMNA1 + " LIKE ?";
        String[] selectionArgs = { textoId.getText().toString() };
        db.delete(Estructura_BBDD.TABLE_NAME, selection, selectionArgs);
        Toast.makeText(getApplicationContext(),"Registro borrado.", Toast.LENGTH_LONG).show();
        textoId.setText("");
        textoNombre.setText("");
        textoApellido.setText("");
    }
});

Botón "Borrar" en Omnis Studio

On evClick
Do lRow.$define(i_ID;i_Nombre;i_Apellido)
Do lRow.$assigncols(i_ID;i_Nombre;i_Apellido)
Do $cinst.$sqlobject.$delete("DELETE FROM Empleados WHERE Id = @[i_ID]";lRow)
              Returns IDdelete

Notemos que en el código Android se ha evitado deliberadamente la incorporación del código necesario para tratar las excepciones, salvo en el caso del botón "Buscar" donde se usa un "try-catch", para controlar el hecho que pueda no encontrarse el registro buscado. Omnis predefine un método para tratar las excepciones denominado "$sqldone", a continuación mostramos un ejemplo de uso:

;  Se ejecuta cada vez que concluye una operación SQL (asíncrona)
;  Abandona el método con el mensaje de error, si se produce.

Do $cinst.$sqlobject.$getlasterrortext() Returns lErr
If lErr<>"OK"
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage(lErr;"Error")
Quit method
End If

;  Se ejecuta uno u otro proceso según el resultado
Switch pID
Case IDselecttables
If pResult.$linecount=0
Do $cinst.$creaTabla()     ;; Si no existe se crea la tabla
End If
Case IDselectfetch
Calculate lRows as pResult.$linecount
If lRows=0
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage("No existe el ID";"Respuesta")
Quit method
End If
Calculate i_Nombre as pResult.C2
Calculate i_Apellido as pResult.C3
Case IDcreatetable
Do $cinst.$showmessage("Tabla creada";"Respuesta")
Case IDinsert
Do $cinst.$showmessage("Inserción realizada";"Respuesta")
Case IDdelete
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage("Entrada borrada";"Respuesta")
Case IDupdate
Do $cinst.$showmessage("Actualización realizada";"Respuesta")
Default
Calculate i_ID as 0
Calculate i_Nombre as ''
Calculate i_Apellido as ''
Do $cinst.$showmessage("Error inesperado")
End Switch

En ocasiones los programadores y compañías dedicadas al desarrollo y mantenimiento de software, nos preguntamos ¿Porqué pagar por una herramienta, cuando existe otra que es gratis?, pero definitivamente puedo decir que en muchas ocasiones lo "barato" sale caro. Omnis Studio permite el desarrollo de aplicaciones para dispositivos móviles (Android, iOS y Windows), aplicaciones de escritorio (MacOS, Windows, Linux) o aplicaciones para la Web, sin necesidad de usar más herramientas que el propio Omnis Studio. El ejemplo de eficacia que hemos expuesto, compara una herramienta que sólo permite el desarrollo para dispositivos Android, por lo que el código resultante no podrá ser ejecutado en (por ejemplo) un dispositivo iOS, en cambio el código Omnis, puede ser ejecutado sin cambio alguno, sobre dispositivos iOS o Windows 10.

Juzguen ustedes mismos sobre si lo "barato" sale caro, llevo trabajando con Omnis Studio por unos 20 años ya, período durante el que las tecnologías han sufrido muchos y diferentes cambios que han hecho, al mismo tiempo, aparecer y desaparecer lenguajes de programación, pero Omnis Studio a sabido adaptarse a los tiempos y a tiempo con gran lujo y esmero.

Programar con Omnis Studio hace que me guste éste trabajo.