2013年12月26日 星期四

[android]AudioTrack使用,用來完成PCM Buffer To Play,並提供Play、Pause、Resume與Stop的說明。

近期,在研究如何用播放buffer PCM,作一個底層的播放,自己控制,不透過MediaPlayer class來控制這些流程,因為工作需要,所以就不說明了,重點放在怎麼做這樣的事情。

1.先init()這個AudioTrack,一開始它會要求你這個AudioTrack的buffer大小,這個取決於你的應用,另外重要的是AudioTrack.MODE_STATIC,這個是說明你這個buffer是一次寫入還是分批寫入,如果你是一次寫入的話那就用MODE_STATIC,分批寫入的話就用MODE_STREAM,但是兩邊的用法不一樣,如果你是想要用MODE_STREAM來完成這樣的事情,那我這篇內文就不適用了。

2.playAudioTrack(short[] data, int offset, int length),這就是播放的function,不過因為我這邊使用的是MODE_STATIC mode,所以offset在這裡都不適用,因為不需要向後加data,所以就只要提供data buf 跟data size即可,注意編碼問題(big little endian),如果你的測試音檔從windows上copy過來,請注意它的編碼,會跟Android不一樣。

3.playpause(),這個就是]pause與resume的function,沒啥好說的,大致上就是按下pause,記住你現在的位置(getPlaybackHeadPosition),resume播放這個位置(setPlaybackHeadPosition)。

4.playstop(),很奇怪的設計,要先pause()後,才可以stop(),直接stop沒作用,似乎下stop指令只有改PLAYSTATE_STOPPED為1而已,要清楚還是要去看他這邊stop後做了哪些事情,我是沒再去看這邊的內容。

5.如果你需要Playback的話,請記得加上OnPlaybackPositionUpdateListener 它會提供兩個function給你。
onMarkerReached:大概的意思當你設定位置到了,它會通知你,透過setNotificationMarkerPosition來設定,這大概的想法就是拿來做播放完畢的通知,通知UI層核時播放完畢

onPeriodicNotification:大概的意思當你設定位置的n倍就會通知你,例如你設定frame=1000,那它1000、2000、3000....都會通知你。

6.這個範例大致上說明了怎麼使用,但不完整,但是該點到的都有點到,但是沒包裝。

AndroidManifest.xml 開權限:
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

Source Code:
public class JWavePlayer implements OnPlaybackPositionUpdateListener {
private static final boolean DBG = true;
private static final String TAG = "JWavePlayer";

private int audioFrequency;
private int audioChannel; // 8k or 16k
private int audioEncoding; // Mono or STEREO
private int audioTrackSize;// 288000/16000=18(s) 每一個TrackSize容納18秒
AudioTrack mAudioTrack; // 8bit or 16bit

public short[] g_data;
public int g_offset;
public int g_length;
public int g_frame;
public JWavePlayer() {
audioFrequency = 16000;
audioChannel = AudioFormat.CHANNEL_OUT_MONO;
audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
audioTrackSize=288000;
}
public void init() {
if (mAudioTrack != null) {
release();
}
int minBufSize = AudioTrack.getMinBufferSize(audioFrequency,
audioChannel, audioEncoding);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, audioFrequency,
audioChannel, audioEncoding, audioTrackSize, AudioTrack.MODE_STATIC);
mAudioTrack.setPlaybackPositionUpdateListener(this);
}

public void playAudioTrack(short[] data, int offset, int length) {
if (data == null || data.length == 0 && mAudioTrack.getPlayState()==mAudioTrack.PLAYSTATE_STOPPED) {
return;
}
try {

mAudioTrack.reloadStaticData();
mAudioTrack.write(data, offset, length);
mAudioTrack.setNotificationMarkerPosition(length/2);
mAudioTrack.play();
} catch (Exception e) {
// TODO: handle exception
Log.i("MyAudioTrack", "catch exception..."+e.getMessage());
}
}
public void playpause(){
try {
if (mAudioTrack.getPlayState()==mAudioTrack.PLAYSTATE_PLAYING){
g_frame=mAudioTrack.getPlaybackHeadPosition();
mAudioTrack.pause();
}else if (mAudioTrack.getPlayState()==mAudioTrack.PLAYSTATE_PAUSED){
mAudioTrack.setPlaybackHeadPosition(g_frame);
mAudioTrack.play();
}
} catch (Exception e) {
Log.i("MyAudioTrack", "catch exception..."+e.getMessage());
}
Log.e("MyAudioTrack",String.valueOf(mAudioTrack.getPlayState()) );
}
public void playStop(){
mAudioTrack.pause();
mAudioTrack.stop();
Log.e("MyAudioTrack",String.valueOf(mAudioTrack.getPlayState()) );
}
public void state(){
Log.d(TAG,"getPlayState:"+mAudioTrack.getPlayState());
//PLAYSTATE_STOPPED 1
//PLAYSTATE_PAUSED 2
//PLAYSTATE_PLAYING 3
Log.d(TAG,"getState:"+mAudioTrack.getState());
//STATE_UNINITIALIZED 0
//STATE_INITIALIZED 1
//STATE_NO_STATIC_DATA 2
//Log.d(TAG,"getStreamType:"+mAudioTrack.getStreamType());
}

public void release() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
}
}
@Override
public void onMarkerReached(AudioTrack track) {
// TODO Auto-generated method stub
Log.e(TAG,"MarkerReached State:"+track.getState());

}
@Override
public void onPeriodicNotification(AudioTrack track) {
// TODO Auto-generated method stub
Log.e(TAG,"PeriodicNotification State:"+track.getState());
}

}

2013年7月4日 星期四

Facebook SDK install some Problem

從facebook sdk上使用時所遇到的一些流程與問題紀錄
官方說明文件:https://developers.facebook.com/docs/getting-started/facebook-sdk-for-android/3.0/

1.Install the Prerequisites
You need Eclipse, the Android SDK, and the ADT Plugin
   就是安裝Eclipse起來,可以使用Android Project就可以。
2.Install the Facebook SDK for Android and the Facebook APK
Download and extract the installation package. Install the Facebook app to your emulator
    下載Facebook SDK並安裝Facebook.apk
3.Import the SDK into Eclipse
Add the SDK as a library project to your workspace, along with the sample projects
   就是import facebook sdk(其他附屬的sample可以不用import 無所謂)
    這邊要注意的就是java compiler版本

4.Run the Samples
Try the sample projects, and add your Android key hash to your Facebook profile
   第一個Run的Sample是這個
  • ProfilePictureSample: demonstrates non-logged-in usage of the profile picture control
原因是這個只是測試facebook是否安裝完成其他設定都不用
   這邊的重點是Library的Add..因為位置不同,記得要重新add
   再來就是import android.support.v4的問題...記得要Add External JARs,這個檔案在Facebook SDK/libs裡面,有些人會copy到自己的project的libs裡面,應該都是可以的。

   先確定第一個sample可以Run 就可以進行下一個步驟了

第二個要測試的AP是
  • HelloFacebookSample: an all-round sample that demonstrates profile access, status updates and photo uploading
主要是要測試Android hash key是否正確,首先要在命令列下打(mac os)
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
切忌不要輸入密碼,直接按Enter既可,會得到一組碼,然後再oncreate中加入下面的code:
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Add code to print out the key hash
    try {
        PackageInfo info = getPackageManager().getPackageInfo(
                "com.facebook.samples.hellofacebook", 
                PackageManager.GET_SIGNATURES);
        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(signature.toByteArray());
            Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
            }
    } catch (NameNotFoundException e) {

    } catch (NoSuchAlgorithmException e) {

    }
執行確認一下android hash key 是否正確。
5.Create a Facebook App
Create a new Facebook app, get its ID and associate your Android key hash with it
這邊重點注意,在Facebook developers中設定New APP的時候Sandbox(沙盒模式)記得要關閉,這樣這個APP才會變成"This app is live",這個沒轉換,也是會無法連結,在
if (session.isOpened()) 
這邊會ㄧ直為false,因為無法登入。

剩下步驟就沒有什麼問題,請參考官方網站說明

2013年5月27日 星期一

跳出UIPickerView來做選擇(有限資料)的做法



雖然覺得這樣的使用有點麻煩(太囉唆),但是還是記錄一下。



.h內的interface中加入UIPickerViewDelegate,UIActionSheetDelegate,UIPickerViewDataSource並且所使用的視圖元件要連接Outlets-Delegate要連接到File's Owners,否則無法抓到回傳的event。 
部分程式碼如下:

1.建立一個button並將Outlets-Delegate要連接到File's Owners
2.建立一個function內容如下,用button來觸發    
    //建立動作表
    UIActionSheet *SpeakSheet=[[UIActionSheet alloc]initWithTitle:@"\n\n\n\n\n\n\n\n\n\n\n\n\n" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:@"set Sepaker", nil];
    //顯示動作表
    [SpeakSheet showInView:self.view];
    
    //建立挑選器視圖
    UIPickerView *SpeakPickerView = [[UIPickerView alloc]init];
    SpeakPickerView.tag=101;
    SpeakPickerView.delegate=self;
    SpeakPickerView.dataSource=self;
    SpeakPickerView.showsSelectionIndicator=YES;
    [SpeakSheet addSubview:SpeakPickerView];
3.如果有連接到File's Owner's就會被觸發,就可以在接到資訊
#pragma mark -
#pragma mark - SpeakPickerView methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    if (pickerView.tag==101){
        return 1;
    }
    return 1;//N個轉軸
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (pickerView.tag==101){
        return SpeakName.count;
    }
    return 1;//每個轉軸N個選項
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    NSLog(@"component:%i  row:%i",component,row);
    if (pickerView.tag==101){
        return [SpeakName objectAtIndex:row];
    }
    return @"error";
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSLog(@"clickedButtonAtIndex %i",buttonIndex);//回傳資料的地方
    //這裡沒寫完,要判斷要切換到誰,不過不重要,因為要換方法,所以就不再寫
    
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    //當選定的時候從這邊抓取值,當按下click之後即可,讀取最正確地值作處理
    NSLog(@"didSelectRow");
}

2013年5月12日 星期日

[Android]製作簡易的自動更新機制

在Android上要怎麼製作簡易的自動更新機制呢?
1.按下一個button,送出去檢查apk版本,並比對網路上的版本,如果一致(不更新),不一致(更新),大概就是這樣,清楚明瞭。

大概幾個重點:
1.取得APK的版本:
   getPackageManager().getPackageInfo(getPackageName(),0).versionName;
2.下載:
   downLoadFile()   //參考此function
3.intent安裝
  Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path,fileName)),"application/vnd.android.package-archive");
startActivity(intent);

完整的code大致上如下所示:
//取得網站上的最新版本
    public void checkUpdateVersion() {
     try {
         //Log.e("tdy", "checkUpdate start");
            URL updateURL = new URL(Versionurl);              
            URLConnection conn = updateURL.openConnection();
            InputStream is = conn.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(is);
            ByteArrayBuffer baf = new ByteArrayBuffer(50);
           
            int current = 0;
            while((current = bis.read()) != -1){
                 baf.append((byte)current);
            }

            /* Convert the Bytes read to a String. */
            final String s = new String(baf.toByteArray());        
           
            /* Get current Version Number */
            s_curVersion = getPackageManager().getPackageInfo(getPackageName(),0).versionName;
            s_newVersion = s;
            //Log.e("tdy",s_curVersion+" = "+s_newVersion);
            if (s_curVersion.equals(s_newVersion)){
             //Log.e("tdy","不需更新");  
             mHandler.post(showVersion);
            }else{
             //Log.e("tdy","需更新");
             mHandler.post(showUpdate);
            }
        } catch (Exception e) {
         //Log.e("tdy","網路發生錯誤");
         e.printStackTrace();         
        }
    }
    //更新資料
    private Runnable showUpdate = new Runnable(){
        public void run(){
         new AlertDialog.Builder(SpeakSettings.this)
         .setTitle("軟體更新")
         .setMessage("目前版本("+s_curVersion+")\n發現新版本("+s_newVersion+"),是否更新?")
         .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int whichButton) {
                         /* User clicked OK so do some stuff */
                   pBar = new ProgressDialog(SpeakSettings.this);
      pBar.setTitle("正在下載");
      pBar.setMessage("請稍候...");
      pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      pBar.setIndeterminate(false);//設置進度條是否不明確
      pBar.setCancelable(true);
      pBar.setProgress(100);
      pBar.show();
      //開始下載
      Thread thread = new Thread(){
            public void run(){
              Message message = new Message();
         message.what = downLoadFile(fileurl, fileName, path);
         msghandler.sendMessage(message);
            }
      };
      thread.start();
      
                 }
         })
         .setNegativeButton("暫不更新", new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int whichButton) {
                         /* User clicked Cancel */
                 }
         })
         .show();
        }
    };
    //show目前版本
    private Runnable showVersion = new Runnable(){
        public void run(){
         new AlertDialog.Builder(SpeakSettings.this)
         .setTitle("軟體更新")
         .setMessage("目前為最新版本("+s_curVersion+")")
         .setNegativeButton("好", new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int whichButton) {
                         /* User clicked Cancel */
                 }
         })
         .show();
        }
    };
    //下載檔案
    public int downLoadFile(String httpUrl, String fileName, String path) {
     try {
      // 當存放文件的文件目錄不存在的時候創建該文件目錄
      File tmpFile = new File(path);
      if (!tmpFile.exists()) {
       tmpFile.mkdir();
      }
      //this is the file to be downloaded
   URL url = new URL(httpUrl);
   //create the new connection
   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
   //set up some things on the connection
   urlConnection.setRequestMethod("GET");
   urlConnection.setDoOutput(true);
   //and connect!
   urlConnection.connect();

   File file = new File(path,fileName);
   //this will be used to write the downloaded data into the file we created
   FileOutputStream fileOutput = new FileOutputStream(file);
   //this will be used in reading the data from the internet
   InputStream inputStream = urlConnection.getInputStream();
   //this is the total size of the file
   int totalSize = urlConnection.getContentLength();
   //variable to store total downloaded bytes
   int downloadedSize = 0;
   //create a buffer...
   byte[] buffer = new byte[1024];
   int bufferLength = 0; //used to store a temporary size of the buffer
   //now, read through the input buffer and write the contents to the file
   while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
    //add the data in the buffer to the file in the file output stream (the file on the sd card
    fileOutput.write(buffer, 0, bufferLength);
    //add up the size so we know how much is downloaded
    downloadedSize += bufferLength;
    //this is where you would do something to report the prgress, like this maybe
    //updateProgress(downloadedSize, totalSize);
    pBar.setProgress(downloadedSize*100/totalSize);    
   }
   //close the output stream when done
   fileOutput.close();
     }catch (Exception e) {
   // TODO: handle exception
      return 0;
  }
        return 1;
    }
    //顯示下載完畢或失敗的event
    public Handler msghandler = new Handler() {
  public void handleMessage(android.os.Message msg) {
   super.handleMessage(msg);
   if (msg.what == 1) {
    Toast.makeText(getApplicationContext(), "下載成功!!", Toast.LENGTH_LONG).show();
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(
      Uri.fromFile(new File(path,fileName)),
      "application/vnd.android.package-archive");
    startActivity(intent);
   } else {
    Toast.makeText(getApplicationContext(), "下載失敗!!", Toast.LENGTH_LONG).show();    
   }
   pBar.cancel();
  }
 };

2013年4月26日 星期五

[Android]設定delay幾秒後,執行某函式的方法。


//宣告一個Handler
Handler myHandler = new Handler();

//幾秒後(delaySec)呼叫runTimerStop這個Runnable,再由這個Runnable去呼叫你想要做的事情
myHandler.postDelayed(runTimerStop,delaySec*1000);


//移除
myHandler.removeCallbacks(runTimerStop);

//主體
private Runnable runTimerStop = new Runnable()
  {
      @Override
      public void run()
      {
         //想要做的事情
      }
   };

2013年4月16日 星期二

[Other]整理一些素材,提升網頁、App質感

剛開始整理,所以應該會很少,只是做個紀錄。

1.各式各樣的底圖,可以來這邊尋找。
subtle patterns: http://subtlepatterns.com/

2.idesign (各式各樣的背景圖)
http://idesigniphone.com

3.make app icon ( 製作符合iOS 或者Android的icon,給他一張1024X1024就可以產生所有的圖)
http://makeappicon.com

4.App Icon Template (提供psd的樣板可以修改,如果你會PS的話)
http://appicontemplate.com/ios8


2013年4月10日 星期三

[iOS]使用MPMoviePlayerViewController來播放mp4,在iOS 6上無法順利播放問題解決方法。

在ios5的版本中,使用以下函式就可以順利播放mp4,但是這個函式在ios6卻會crash掉,最後終於找到在ios5與ios6可以使用的方法,詳情請參考該網址

原本在ios5上的寫法如下:(ios6將無法使用)


- (void)openMP4:(NSString *)s_url
{
    NSURL *fileURL = [NSURL URLWithString:s_url];
    [player.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
    [player.moviePlayer setFullscreen:NO];
    player = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
    //弹出播放器窗口
    [self  presentMoviePlayerViewControllerAnimated:player ];
    [player.moviePlayer setMovieSourceType:MPMovieSourceTypeFile];
    [player.moviePlayer prepareToPlay];
    [self.view addSubview:player.view];
    //播放
    [player.moviePlayer play];
    //增加一個觀察者
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayBackDidFinish:)
                                                 name:MPMoviePlayerPlaybackDidFinishNotification
                                               object:nil];
}
- (void) moviePlayBackDidFinish:(NSNotification*) aNotification {
    //移除觀察者
    [[NSNotificationCenter     defaultCenter] removeObserver:self
                                                        name:MPMoviePlayerPlaybackDidFinishNotification
                                                      object:nil];
    //播放器消失
    [player dismissMoviePlayerViewControllerAnimated];
    player=NULL;
}

相容ios5、ios6的寫法如下(來源):

- (void)openMP4:(NSString*)s_url
{
    // Initialize the movie player view controller with a video URL string
    NSURL *fileURL = [NSURL URLWithString:s_url];
    
    MPMoviePlayerViewController *playerVC = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
    
    // Remove the movie player view controller from the "playback did finish" notification observers
    [[NSNotificationCenter defaultCenter] removeObserver:playerVC
                                                    name:MPMoviePlayerPlaybackDidFinishNotification
                                                  object:playerVC.moviePlayer];
    
    // Register this class as an observer instead
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(movieFinishedCallback:)
                                                 name:MPMoviePlayerPlaybackDidFinishNotification
                                               object:playerVC.moviePlayer];
    
    // Set the modal transition style of your choice
    playerVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    
    // Present the movie player view controller
    [self presentModalViewController:playerVC animated:YES];
    
    // Start playback
    [playerVC.moviePlayer prepareToPlay];
    [playerVC.moviePlayer play];
}
- (void)movieFinishedCallback:(NSNotification*)aNotification
{
    // Obtain the reason why the movie playback finished
    NSNumber *finishReason = [[aNotification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
    
    // Dismiss the view controller ONLY when the reason is not "playback ended"
    if ([finishReason intValue] != MPMovieFinishReasonPlaybackEnded)
    {
        MPMoviePlayerController *moviePlayer = [aNotification object];
        
        // Remove this class from the observers
        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:MPMoviePlayerPlaybackDidFinishNotification
                                                      object:moviePlayer];
        
        // Dismiss the view controller
        [self dismissModalViewControllerAnimated:YES];
    }
}

2013年3月29日 星期五

[iOS]使用非同步方式透過NSURLConnection上傳檔案-以圖片檔案為例

如果要使用非同步的方式來上傳檔案的話,則需要設定NSURLConnectionDelegate來接收回傳值並且宣告一個NSMutableData來接收。


SampleViewController.h


@interface SampleViewController : UIViewController <NSURLConnectionDelegate> {
    NSMutableData *receivedData;//NSURLConnectionDelegate使用
}
@property (nonatomic, strong) NSMutableData *receivedData;
@end


與同步的做法,差別在於這邊使用
[NSURLConnection connectionWithRequest:request delegate:self];
來傳遞,透過delegate 來接收回傳的event

SampleViewController.m


@implementation MemberViewController
@synthesize receivedData;


- (void)uploadFileDelegate:(NSString *)url fileData:(NSData *)paramData filePath:(NSString *)path{
    self.receivedData=[[NSMutableData alloc] init];
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
    [request setTimeoutInterval:30];
    [request setHTTPMethod:@"POST"];
    
    NSString *boundary = @"0xKhTmLbOuNdArY";//NSURLConnection is very sensitive to format.
    // set Content-Type in HTTP header
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    // post body
    NSMutableData *body = [NSMutableData data];
    
    // add params (all params are strings)
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"path"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n",path] dataUsingEncoding:NSUTF8StringEncoding]];
    
    // add image data   
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", @"file"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:paramData];
    [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    // setting the body of the post to the reqeust
    [request setHTTPBody:body];
    // set the content-length
    NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    
    // set URL
    [request setURL:[NSURL URLWithString:url]];
    
    [NSURLConnection connectionWithRequest:request delegate:self];
    //進入NSURLConnection Delegate
}
#pragma mark -
#pragma mark NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    // store data
    NSLog(@"didReceiveResponse");
    [self.receivedData setLength:0];      //通常在這裡會先清空回傳值的暫存
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSLog(@"didReceiveData");
    [self.receivedData appendData:data];    //可能多次收到多次回傳值,把新的回傳值加在原有回傳值後面
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    // 錯誤例外處理
    NSLog(@"didFailWithError");
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // disconnect
    NSString *checkData=[NSString stringWithFormat:@"%@",[[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]];
}

2013年3月28日 星期四

[PHP]透過php_curl.dll來呼叫Web Service 互傳資料

用來與server溝通 傳遞參數: {name:123,password:123}
$toURL,   
  CURLOPT_HEADER=>0,   
  CURLOPT_VERBOSE=>0,   
  CURLOPT_RETURNTRANSFER=>true,   
  CURLOPT_USERAGENT=>"Mozilla/4.0 (compatible;)",   
  CURLOPT_POST=>true,   
  CURLOPT_POSTFIELDS=>http_build_query($post), 
  ); 
 curl_setopt_array($ch, $options); 
 // CURLOPT_RETURNTRANSFER=true 會傳回網頁回應, 
 // false 時只回傳成功與否 
 $result = curl_exec($ch);  
 curl_close($ch); 
 return $result; 
}
//接收POST參數的URL 
$url = '你要連結的url';
$postdata = array('Name'=>'123','password'=>'123');//要上傳的data 
$getData = my_curl($url,$postdata);
echo $getData."

";//回傳資料 
?>

2013年3月27日 星期三

[IOS]使用同步方式透過NSURLConnection上傳檔案-以圖片檔案為例

使用同步的方式上傳圖片檔
呼叫:

//上傳的url,上傳的image data 一個檔案file:image.jpg 一個參數path:path
NSString *result=[self uploadFile:url fileData:data filePath:path];

函式:


- (NSString *)uploadFile:(NSString *)url fileData:(NSData *)paramData filePath:(NSString *)path{
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
    [request setTimeoutInterval:30];
    [request setHTTPMethod:@"POST"];
    
    NSString *boundary = @"0xKhTmLbOuNdArY";//NSURLConnection is very sensitive to format.
    // set Content-Type in HTTP header
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    // post body
    NSMutableData *body = [NSMutableData data];
    
    // add params (all params are strings)
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"path"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n",path] dataUsingEncoding:NSUTF8StringEncoding]];
    
    // add image data
    
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", @"file"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:paramData];
    [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    
    [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    // setting the body of the post to the reqeust
    [request setHTTPBody:body];
    // set the content-length
    NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    
    // set URL
    [request setURL:[NSURL URLWithString:url]];
    
    NSData *returnData=[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    //看returnData出來的值
    NSLog(@"%@",[[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]);
    NSString *checkData=[NSString stringWithFormat:@"%@",[[NSString alloc] 
    return checkData;  
}

[iOS]將相片的圖片轉正顯示


如果顯示UIImage時,發現圖片反了,或者是需要轉90度,使用這個函式會自動幫你轉正顯示

呼叫:


UIImage* image =[self rotateImage:image];


函式:


- (UIImage *)rotateImage:(UIImage *)aImage {
    CGImageRef imgRef = aImage.CGImage;
    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);
    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    CGFloat scaleRatio = 1;
    CGFloat boundHeight;
    UIImageOrientation orient = aImage.imageOrientation;
    switch(orient) {
        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;
        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;
        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(width, height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;
        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(height, width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;
        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;
        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;
        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;
        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
    }
    UIGraphicsBeginImageContext(bounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    } else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }
    CGContextConcatCTM(context, transform);
    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return imageCopy;
}