现在的位置: 首页 > 移动开发> 正文
Extending AIR for Android (2)
2011年07月02日 移动开发 暂无评论 ⁄ 被围观 2,789+

System Notifications and Services

AIR for Android applications don’t yet have an API to do Android system notifications. But you can add system notifications to your AIR for Android application through a startup hook. In order for the AIR application to communicate with the native Android APIs you must provide a bridge for the communication. The simplest way to create that bridge is using a network socket. The Android application can listen for data on the socket and then read that data and determine if it needs to display a system notification. Then the AIR application can connect to the socket and send the necessary data. This is a pretty straightforward example but some security (for instance a key exchange) should be implemented to insure that malicious apps don’t discover and abuse the socket. Also some logic to determine which socket should be used would likely be necessary.

1. Inside the application section add a new Android Service:

   <service android:enabled="true" android:name="TestService" />

2. Since this example uses a Socket you will also need to add the INTERNET permission:

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

3. You might also want to enable the phone to vibrate when there is a new notification. If so add that permission as well:

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

4. Save your changes to AndroidManifest.xml.

5. Next, create the background Java Service class, called TestService. This service will listen on a socket and when necessary, display an Android Notification:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package com.jamesward;   
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;   
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;   
 
public class TestService extends Service {  
    private boolean stopped=false;  
 private Thread serverThread;  
 private ServerSocket ss;     
 
 @Override 
 public IBinder onBind(Intent intent){ 
       return null;  
 }     
 
 @Override  public void onCreate()   {
        super.onCreate();       
  Log.d(getClass().getSimpleName(), "onCreate");         
 
  serverThread = new Thread(new Runnable() {           
         public void run()  {                
           try  {                        
         Looper.prepare();                        
      ss = new ServerSocket(12345);                        
      ss.setReuseAddress(true);                        
      ss.setPerformancePreferences(100, 100, 1);                        
 
      while (!stopped)   {   
          Socket accept = ss.accept();                                
       accept.setPerformancePreferences(10, 100, 1);                                
       accept.setKeepAlive(true);                                   
       DataInputStream _in = null;                                
 
       try   {                                        
           _in = new DataInputStream(new BufferedInputStream(accept.getInputStream(),1024));  
       }  catch (IOException e2)  {                                  
           e2.printStackTrace();                                
       }                                   
 
       int method =_in.readInt();                                   
       switch (method) {                                  
        // notification                                  
        case 1: 
            doNotification(_in);
         break;                                
          }                        
      }                
     }   catch (Throwable e)  {                        
         e.printStackTrace();                        
      Log.e(getClass().getSimpleName(), "Error in Listener",e);                
     }                   
 
     try {                  
         ss.close();                
     }  catch (IOException e)  {                  
         Log.e(getClass().getSimpleName(), "keep it simple");                
     }        
    }           
   },"Server thread");      
 
  serverThread.start();     
 }     
 
 private void doNotification(DataInputStream in) throws IOException {    
      String id = in.readUTF();    
   displayNotification(id);  
    }     
 
 @Override 
 public void onDestroy() {          
    stopped=true;          
    try {                  
       ss.close();          
    } catch (IOException e) {}          
 
    serverThread.interrupt();          
 
    try {                  
       serverThread.join();          
    } catch (InterruptedException e) {}  
 }     
 
 public void displayNotification(String notificationString)   {    
     int icon = R.drawable.mp_warning_32x32_n;    
  CharSequence tickerText = notificationString;    
  long when = System.currentTimeMillis();    
  Context context = getApplicationContext();    
  CharSequence contentTitle = notificationString;    
  CharSequence contentText = "Hello World!";       
  Intent notificationIntent = new Intent(this, MainApp.class);    
  PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);       
  Notification notification = new Notification(icon, tickerText, when);    
  notification.vibrate = new long[] {0,100,200,300};       
  notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);       
  String ns = Context.NOTIFICATION_SERVICE;    
 
  NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);       
  mNotificationManager.notify(1, notification);  
 }   
}
package com.jamesward;   
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;   
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;   

public class TestService extends Service {  
    private boolean stopped=false;  
 private Thread serverThread;  
 private ServerSocket ss;     

 @Override 
 public IBinder onBind(Intent intent){ 
       return null;  
 }     

 @Override  public void onCreate()   {
        super.onCreate();       
  Log.d(getClass().getSimpleName(), "onCreate");         

  serverThread = new Thread(new Runnable() {           
         public void run()  {                
           try  {                        
         Looper.prepare();                        
      ss = new ServerSocket(12345);                        
      ss.setReuseAddress(true);                        
      ss.setPerformancePreferences(100, 100, 1);                        

      while (!stopped)   {   
          Socket accept = ss.accept();                                
       accept.setPerformancePreferences(10, 100, 1);                                
       accept.setKeepAlive(true);                                   
       DataInputStream _in = null;                                

       try   {                                        
           _in = new DataInputStream(new BufferedInputStream(accept.getInputStream(),1024));  
       }  catch (IOException e2)  {                                  
           e2.printStackTrace();                                
       }                                   

       int method =_in.readInt();                                   
       switch (method) {                                  
        // notification                                  
        case 1: 
            doNotification(_in);
         break;                                
          }                        
      }                
     }   catch (Throwable e)  {                        
         e.printStackTrace();                        
      Log.e(getClass().getSimpleName(), "Error in Listener",e);                
     }                   

     try {                  
         ss.close();                
     }  catch (IOException e)  {                  
         Log.e(getClass().getSimpleName(), "keep it simple");                
     }        
    }           
   },"Server thread");      

  serverThread.start();     
 }     

 private void doNotification(DataInputStream in) throws IOException {    
      String id = in.readUTF();    
   displayNotification(id);  
    }     

 @Override 
 public void onDestroy() {          
    stopped=true;          
    try {                  
       ss.close();          
    } catch (IOException e) {}          

    serverThread.interrupt();          

    try {                  
       serverThread.join();          
    } catch (InterruptedException e) {}  
 }     

 public void displayNotification(String notificationString)   {    
     int icon = R.drawable.mp_warning_32x32_n;    
  CharSequence tickerText = notificationString;    
  long when = System.currentTimeMillis();    
  Context context = getApplicationContext();    
  CharSequence contentTitle = notificationString;    
  CharSequence contentText = "Hello World!";       
  Intent notificationIntent = new Intent(this, MainApp.class);    
  PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);       
  Notification notification = new Notification(icon, tickerText, when);    
  notification.vibrate = new long[] {0,100,200,300};       
  notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);       
  String ns = Context.NOTIFICATION_SERVICE;    

  NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);       
  mNotificationManager.notify(1, notification);  
 }   
}

This service listens on port 12345. When it receives some data it checks if the first “int” sent is “1”. If so, it then creates a new notification using the next piece of data (a string) that is received over the socket.

6. Modify the MainApp Java class to start the service when the onCreate() method is called:

1
2
3
4
5
6
7
8
9
10
11
@Override   
public void onCreate(Bundle savedInstanceState) {        
   try {            
      Intent srv = new Intent(this, TestService.class);            
   startService(srv);        
   }  catch (Exception e)  {            
     // service could not be started        
   }           
 
   super.onCreate(savedInstanceState);    
}
@Override   
public void onCreate(Bundle savedInstanceState) {        
   try {            
      Intent srv = new Intent(this, TestService.class);            
   startService(srv);        
   }  catch (Exception e)  {            
     // service could not be started        
   }           

   super.onCreate(savedInstanceState);    
}

That is all you need to do in the Android application.

7. Next, create a Flex application that will connect to the socket and send the right data. Here is some sample code for my Notifier.mxml class, which I used to test the Android service:

  <?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"  xmlns:s="library://ns.adobe.com/flex/spark">   
     <fx:Style>    @namespace s "library://ns.adobe.com/flex/spark";    
            global {  fontSize: 32;   } 
     </fx:Style>  

     <s:layout>   
         <s:VerticalLayout horizontalAlign="center" paddingTop="20"/>  
     </s:layout>   

     <s:TextInput id="t" text="test test"/>   
     <s:Button label="create notification">  

     <s:click>   
       <![CDATA[        
              var s:Socket = new Socket();       
              s.connect("localhost", 12345);       
              s.addEventListener(Event.CONNECT, function(event:Event):void {         
                                             trace('connected!');          
                                             (event.currentTarget as Socket).writeInt(1);         
                                             (event.currentTarget as Socket).writeUTF(t.text);         
                                             (event.currentTarget as Socket).flush();         
                                             (event.currentTarget as Socket).close();        });      

               s.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent):void {      
                                               trace('error! ' + event.errorID);        });      

               s.addEventListener(ProgressEvent.SOCKET_DATA, function(event:ProgressEvent):void {        
                                               trace('progress ');        });    

            ]]>   

     </s:click>  

     </s:Button>

    </s:Application>

As you can see there is just a TextInput control that allows the user to enter some text. Then when the user clicks the Button the AIR for Android application connects to a local socket on port 12345, writes an int with the value of 1, writes the string that the user typed into the TextInput control, and finally flushes and closes the connection. This causes the notification to be displayed.

8. Now simply compile the Flex app and overwrite the assets/app.swf file with the new Flex application. Check out a video demonstration of this code.

原文作者:james ward

给我留言

留言无头像?


×
腾讯微博