2015年11月18日 星期三

iOS Enterprise in house發佈app記錄

最近在搞apple enterprise developer 的事情

 在搞 in house的部份,

 在iOS7.1之後有了些許的改變

 發現原來有兩年沒有發佈in house的app了

 在iOS9中,發佈in house的app 

 XCode會compile出一個plist與一個ipa檔

 檔案需放至在https的server裡頭

 我用以前的邏輯去建立出enterprise的App測試

 但不知為何 

發現放在自己的建立的https server就一直無法成功下載 

後來將檔案與網頁檔放到dropbox上,

居然可以下載安裝 這就奇怪了 

流程明明就一樣

所以就開始朝向https server找原因

 oh 對了,

網頁是要提供使用者下載App的連結,

 通常連結比較特別(html) 要如下:

 
<a href="https://www.blogger.com/null" ref="itms-services://?action=download-manifest?&url=http://domain/manifest.plist">下載App</a>;

manifest.plist就是你發佈出來的其中一個檔案

 若你的下載的路徑不同的話,

可以開啟plist去修改裡面的網址

 在說https server之前 

我先說明一下若放到dropbox的作法

 首先你要有dropbox的帳號

 先上傳你寫好的網頁檔(html) 點選右鍵 分享鏈結 然後你會得到

https://www.dropbox.com/s/xxxxxxxxxxx/xxxx.html

www.dropbox.com

改成

dl.dropboxusercontent.com

然後你可以先由此網址確認網頁是否能夠打得開

若打得開就代表是成功

再來就把你的ipa檔放到dropbox上面

然後一樣的方式

先取得ipa的分享網址 記得改上面紅色的字

再把ipa的分享網址到plist裡面修改 因為plist檔裡會有一個是指向ipa的位置

再把plist上傳到dropbox 一樣的方式取得分享連結

再改上面紅色的位置 把網址copy下來

再貼到html的超連結

超連結改完後再上傳到dropbox 並且覆蓋

這樣就能夠由dropbox 的網頁下載安裝 ipa檔


以上是放到dropbox的方式

然後實際我一直卡在是  https已經架了起了

但卻一直出現 "無法連結xxx.xxx.xxx.xx" (沒有放到https server 好像也也類似的錯誤訊息)

後來發現是https的證問題

網路上有人說ios9要購買外面的SSL授權?!

我想這不就要花了一筆錢

但後來發現其實不然

你要去查如何用SSL去建立出一個CSR檔

再利用CSR檔去建立出一個https可以使用的keystore

然後iOS手機要先至https下載CSR憑證 

就可以跳過無法連結xxx.xxx.xxx.xxx的問題

好 以為這樣就很順利了

但what the fuxk!!!

為啥又出現

Unable to download App
xxx not be download at this time
(繁中:無法下載應用程序此時無法安裝xxx xx ”)

為了以上的問題 我煩惱了三天

為了in house下載煩惱了四天

所以一個星期就過了....

後來發現一件很蠢的問題

就是手機裡有原本App的profile檔

也就是之前實機測試裝上去的

把他砍了 重新執行下載

就能夠順利安裝了…

in house的資料是不多 且apple一直在改變

像我最無法安裝時 有查到以下的 解法

Targets → Select your target
            → Build Settings
              → Code Signing Resource Rules Path
 加入   $(SDKROOT)/ResourceRules.plist

但我加入還是不能
但這應該都是憑證的問題 

也可以參考以下教學網址試試

2015年11月5日 星期四

ios Singleton

UserInfoManagerCenter.h
#import <Foundation/Foundation.h>

@interface UserInfoManagerCenter : NSObject

@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSNumber *age;

+(instancetype)managerCenter;
@end

UserInfoManagerCenter.m
#import "UserInfoManagerCenter.h"
static UserInfoManagerCenter *center = nil;
@implementation UserInfoManagerCenter
+(instancetype)managerCenter{

    static dispatch_once_t predicate;
    // 避免產生競爭現像
    dispatch_once(&predicate, ^{
        center = (UserInfoManagerCenter *)@"UserInfoManagerCenter";
        center = [[UserInfoManagerCenter alloc] init];
    });
    
    // 防止子類別使用
    NSString *classString = NSStringFromClass([self class]);
    // 使用方法的class名字與UserInfoManagerCenter不同 就crash
    if( [classString isEqualToString:@"UserInfoManagerCenter"] == NO ){
        // crash
        NSParameterAssert(nil);
    }
    
    return center;
}

-(instancetype)init{
    NSString *string = (NSString*)center;
    if( [string isKindOfClass:[NSString class]] == YES && [string isEqualToString:@"UserInfoManagerCenter"]){
        self = [super init];
        if( self){
            // 防止子類別使用
            NSString *classString = NSStringFromClass([self class]);
            // 使用方法的class名字與UserInfoManagerCenter不同 就crash
            if( [classString isEqualToString:@"UserInfoManagerCenter"] == NO ){
                // crash
                NSParameterAssert(nil);
            }
            

        }
        return self;
    }else{
        return nil;
    }
    
    
}
@end



使用
UserInfoManagerCenter *center = [UserInfoManagerCenter managerCenter];

    NSLog(@"%@",center.name);

2015年10月30日 星期五

iOS開發者帳號購買價格功能表參考


自從iOS Xcode 7開始,

你不需新購買Developer 帳號就可以直接發佈在實機測試App

可是你還是需有一組Apple ID

但有些功能是有限制的 

可以參考下表









2015年9月23日 星期三

Swift Call Objective-C方式

iOS裡要如何呼叫Objective-C的語法呢

Swift會透過一個Bridge去呼叫Objective-C

首先先建立一個Swift的iOS Project

再建立一個Objective語法的檔案 叫做Member

會產生Member.h 與Member.m

當建立後 會跳出這個畫面


若有產生就按Yes

沒有產生就別擔心 可以手動建立

沒產生的話就手動建立一個檔名為

swiftCallObjCTest-Bridging-Header.h的檔案

swiftCallObjCTest為你的專案名稱 自行修改

若自行新增的使用者 要去Build Setting檢查一下有沒有新增這項檔案


再來在Member.h新增objective-c的語法



#import <Foundation/Foundation.h>

@interface Member : NSObject

@property (nonatomic,strong) NSString *name;

@end


接下來再切到AppDelegate.swift的檔案

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 裡面

加入

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        var member: Member = Member()
        member.name = "James"
        println("member name:\(member.name)")
        return true
    }


這樣就可以對Objective-C的屬性做存取囉!

2015年9月17日 星期四

Eclipse 設Java 1.8路徑

下載 Java SE Development Kit 8u51 

http://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html#jdk-8u51-oth-JPR


Eclipse 設Java 1.8路徑
/Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home


2015年9月11日 星期五

恆逸OCPJP認證班課程心得

其實參加這門課程已經兩年過去了

當時原本想說去把Java基礎打的更扎實,然後順便去考個證照,交個強者朋友

但後來上完課後最後決定沒去考試

因為報名費覺得太貴

且真正有學到的東西最重要,證照只是面試多個機會罷了,

最重要是你的基礎與經驗在哪裡

這門課原本以為老師會與許多仿間進修課程一樣會以題庫式的引導去學習

幸好不是這樣子!

很感謝老師從頭基礎的打起,雖然在學校已有學過Java

但許多Java的細節與觀念,都是在這個課程裡才學到的。

使我至今兩年過去,還是會去翻閱當時的上課講義

回想當時老師所提到的內容,並且實際應用在工作上。

記得當初在上課時,要去上這麼昂貴的課程,並且在學校就有學過的東西,

真的令人非常的猶豫,下班後要上課非常的辛苦,下班即要 趕至台北恆逸教育訓練中心上課

上到晚間十點才帶著疲憊的身軀回到家,但每次上完課後,

內心是充實的,感覺一天有所成長的而是在晚間恆逸上課的時候~

台北恆逸的上課環境我覺得相較於其它訓練中心,環境乾淨整體讓人又感到舒適,

老師也是充滿著經驗,且對自己的領域非常的專精,相對的學費不便宜,

但這樣的學費由充滿經驗的老師與優質的教學訓練環境是對等的。

自從上OCPJP課程後,我也愛上了這個地方,

總是希望能夠在這裡學到許多扎實並且實用的技能,

讓我能夠在工作上領先許多不同的同事們。

自從上過OCPJP課程後,也再次來恆逸學習HTML5與CSS3課程,到現在

趁著公司的教育訓練也報名了Swift程式語言課程。

利用工作後的時間去上課辛苦 但在我們的心靈與腦袋都無形的提升了不少!

若自己學習感到枯燥乏味,想參加教育訓練課程,真心推薦可以選擇恆逸

這裡可以讓你有扎實的學習內容 乾淨的環境 與態度良好的服務人員!

最重要的是有充滿經驗的老師,能夠讓你進入專業的領域與思維。

若對恆逸的課程有興趣可以參考下方的網址

恆逸教育訓練中心http://www.uuu.com.tw

常會有新的課程開班可以選擇,你可以試者存幾個月的錢,去體會一次課程,

不會讓你失望的。

2015年6月2日 星期二

Android Studio 使用Git設定

Android Studio 使用Git設定

1. 先到Android Studio VCS→ Import into Version Control → Create Git Repository

2. 在GitLab或GitHub上建立專案。

3. 將Git上面的指令選擇Https, Git init那幾行指令 貼到你的terminal

4. 專按右鍵Git→Add 後 就可以進行commit 、push

2015年5月21日 星期四

Sketch 初次接觸

前陣子太忙,

最近終於有機會接觸一些有趣的東西,

就是現在很紅的Sketch,

載了試用版下來試著做一個App的登入頁 如下:


Sketch內包含了ios許多的ui元件可以直接套用,

對於UI設計是一個很好用的工具~


2015年4月23日 星期四

[Java] Insert sort 插入排序法

Java:
public class InsertSort {
    int data[] = new int[6];
    int size = data.length;


    public static void main(String args[])
    {
        System.out.print("123");
        InsertSort is = new InsertSort();
        is.inputarr();
        is.showData();
        is.insert();
    }
 void inputarr()
    {
        int i;
        for( i = 0 ; i<size; i++)
        {
            try{
                System.out.print("please input:"+(i+1) +"element:");
                InputStreamReader isr = new InputStreamReader(System.in);
                BufferedReader br = new BufferedReader(isr);
                data[i] = Integer.parseInt(br.readLine());
            }
            catch (Exception e)
            {

            }

        }
    }
 void showData()
    {
        int i;
        for(i = 0 ; i<size;i++)
        {
            System.out.print(data[i]+" ");

        }
        System.out.print("\n");
    }


時間複雜度為:O(n^2)
最壞及平均需較(n-1) + (n-2)+....3+2+1 = n(n-1)/ 2次

insert sort建議在錄結串列上使用,因為會常造成資料的大量搬移。

2015年4月18日 星期六

XCode6.3惱人的bug

升到XCode 6.3發現一個惱人的Bug

明明就有一隻手機是ios 8.1.2版

project設定 iOS Deployment Target 為 8.0版本

照理說8.0以上的手機都要可以發佈至實機上(以正確的憑證狀況下),

但升到XCode6.3 卻無法傳app至8.1.2、8.2 的iOS手機

而iOS 8.3的手機卻可以!!

不可能要我把所有裝置都升級到8.3

這個bug 是你無法選擇你的裝置,

會出現 ineligible Devices.



後來找到解法!!!!

只要你到Product→Destionation→選擇你的裝置


左上角就會直接跳到你的手機,就可以發佈了.....|||||||


2015年3月23日 星期一

解決Xcode外掛無法使用問題

解決xcode下外掛無法使用

到以下目錄

~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/

找到你要的外掛 打開套件內容

選擇info.plist檔,

於DVTPluginCompatibilityUIDs加入

XCodde 6.3.2
E969541F-E6F9-4D25-8158-72DC3545A6C6
並執行
find ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins -name Info.plist -maxdepth 3 | xargs -I{} defaults write {} DVTPlugInCompatibilityUUIDs -array-add `defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID`

XCode 6.3
9F75337B-21B4-4ADC-B558-F9CADF7073A7
Xcode 6.2
A16FF353-8441-459E-A50C-B071F53F51B7

Xcode 6GM:
C4A681B0-4A26-480E-93EC-1218098B9AA0


2015年3月12日 星期四

iOS Container view與Parent UIViewController的溝通



若parent裡要呼叫container裡面的屬性




self.ChildViewController.yourProperty = yourValue




若container要呼叫parent的屬性:




((YourParentViewControllerClassType *)self.parentViewController).yourParentProperty = TheValueYouWant;

2015年3月2日 星期一

UIContainer View呼叫Parent ViewController屬性與傳值

UIContainer VIew 傳值給ParentViewController




主要是選擇使用delegate的方式,

在ParentViewController.h



#import 
#import "ChildViewController.h"

@interface ViewController : UIViewController<ChildViewControllerDelegate>

@property (weak, nonatomic) IBOutlet UITextField *parentTF;

@end


ParentUIViewController .m  檔

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([segue.identifier isEqualToString:@"mySegue"])
    {
        ChildViewController *cVC = segue.destinationViewController;
        cVC.delegate = self;
    }
}

-(void) done:(NSString *)someText andChildBtn:(UIButton *)childBtn
{
    self.parentTF.text = someText;
    [childBtn setTitle:@"changed" forState:UIControlStateNormal];
    [self.view setBackgroundColor:[UIColor darkGrayColor]];
}
@end


而在 ChildViewController.h 要宣告定義好protocol讓UIViewController能夠處理你要他做的事情



#import <UIKit/UIKit.h>
// 傳到到另個 ViewController ,所以自己要先定義protocol
@protocol ChildViewControllerDelegate <NSObject>

-(void)done:(NSString*)someText andChildBtn:(UIButton*)childBtn;

@end

@interface ChildViewController : UIViewController

@property(nonatomic,assign) id<ChildViewControllerDelegate> delegate;

@property (weak, nonatomic) IBOutlet UIButton *passValueBtn;
@property (weak, nonatomic) IBOutlet UITextField *childTF;
- (IBAction)passValueAction:(id)sender;
@end



然後.m檔去呼叫delegate方法

#import "ChildViewController.h"

@implementation ChildViewController

- (IBAction)passValueAction:(id)sender {
    
    [self.delegate done:self.childTF.text andChildBtn:self.passValueBtn];
}
@end


這樣就可以透過container view controller去傳值給parentviewcontroller

而還有夠簡易的方式是

直接由container view controller去修改parent view controller的值

例如


 ((ViewController*)self.parentViewController).lb.text =[NSString stringWithFormat:@"%ld",indexPath.row];

以上是由container view 呼叫 parent view的屬性

2015年2月12日 星期四

Objective-C 字串比較

一般自定常數的方法有兩種,

1.  在header(.h)檔

FOUNDATION_EXPORT NSString * const MY_NAME;
FOUNDATION_EXPORT NSString * const MY_GIRLFRIEND_NAME;

於.m檔

NSString * const MY_NAME = @"James";
NSString * const MY_GIRLFRIEND_NAME = @"Stella";

2. 另一種定義常數的方法為:

#define MY_NAM @"James"
#define MY_GIRLFRIEND_NAME  @"Stella"

這兩種方法在檢查字串時,第一種可以使用(StringInstance == MY_NAME )來比較,

而使用define則是使用([StringInstance isEqualToString:MY_NAME]) 來比較。

第一種直接比較是使用pointer address,第二種比較則是比較每個字元是否相等。


2015年1月26日 星期一

gen_entitlements.py: No such file or directory實機報錯

今天要把別的廠商的專案進行測試

但拿到專案檔一直無法傳到手機上,

以為是憑證哪出了問題,但後來發現不是!

錯誤訊息部份如下

line 4: /Applications/Xcode.app/Contents/Developer/iphoneentitlements/gen_entitlements.py: No such file or directory




後來發現這個是之前公司在作假憑證的run script出了問題

只要到build phase裡刪除 run script

再使用正確的debug憑證去發佈至手機即可