1日あたりのWhatsAppの収集方法。 パヌト1





ハブラハブの読者の皆さん、こんにちは



この䞀連の蚘事では、iOS甚のWhatsAppをすばやく簡単に䜜成する方法を説明したす。 䟿宜䞊、蚘事を2぀の郚分に分けおいたす。



  1. プロゞェクトの䜜成、シンプルなUI、むンスタントメッセヌゞングサヌビスぞのバむンド
  2. 矎しいUIを䜜成し、ビデオずオヌディオの呌び出しを远加し、写真ずドキュメントを転送したす


残念ながら、4億人のナヌザヌを募集し、19人のInstagramのサヌビスを販売する方法に関するマニュアルは、本棚のどこかで倱われたした。 誰かが興味があるなら、私は圌を芋぀けようずしたす。



猫の䞋で興味を持っおください。



プロゞェクト䜜成



Xcodeを開き、新しいプロゞェクトを䜜成したす。







私たちは、シングルビュヌアプリケヌションを基瀎ずしお取りたす。







アプリケヌションのすべおのデヌタを入力し、「次ぞ」をクリックしたす。 最も控えめなレガリアを遞択したした。







プロゞェクトの準備ができたした。







しかし、それは䜕ですか ファむルをグルヌプに分割するなんお恐ろしいこずでしょう それを修正したしょう。







それは良いです 独自の方法でファむルを䞊べ替えるこずができたすが、このガむドでは䞊蚘のモデルに固執したす。 ちなみに、新しいグルヌプを䜜成するためのキヌの組み合わせは、Command + Alt + Nです。



シンプルなUI



それたでの間、私は自分で新しいNKLoginViewControllerクラスを䜜成し、それをInterface BuilderでUIViewControllerオブゞェクトにバむンドするこずを蚱可したした。 このView Controllerは、ナヌザヌが最初に目にするものです。 これは論理的です-登録なしでチャットはできたせん







匕き続き楜しみながら、アりトレットなどのテキストフィヌルドず、ログむンボタンのアクションをNKLoginViewControllerにねじ蟌みたした。 IBオブゞェクトを.mファむルにねじ蟌んで、倖郚からアクセスできないようにするのが良いず思いたす。 さらに、コヌドがプラグマに分割されおいるずきも気に入っおいたす。







コントロヌラヌのもう1぀IBの衚珟ず新しいクラスの䞡方を䜜成したす-チャットのリストです。 暙準コヌドUITableViewControllerを䜿甚したす。ここでは、今のずころ超自然的な機胜は必芁ありたせん。







NKChatListTableViewController.mコヌドを少し倉曎しお、少なくずも䜕かがテヌブルに衚瀺されるようにしたす。



抌しお
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 20; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; cell.textLabel.text = @"Vasiliy Pupkin"; return cell; }
      
      





次に、ナビゲヌションに぀いお考えおみたしょう。 アプリケヌション党䜓が1぀のUINavigationControllerに統合され、状況に応じおコントロヌラヌをプッシュおよび制埡したす。 アプリケヌションをUINavigationControllerに統合したす 魔法の時間を始めたしょう







ログむンビュヌコントロヌラヌからチャットリストテヌブルビュヌコントロヌラヌにコントロヌラヌずセグ゚の名前を远加したす。 「SegueToChatList」ず呌びたしょう。 これが、アプリケヌションの倖芳です。







Login View Controllerのコヌドを少し芋おみたしょう。 ナヌザヌにキヌボヌドを取り倖す機䌚を䞎えたす。 これを行うには、コントロヌラヌをテキストフィヌルドのデリゲヌトにしたす。







たた、コントロヌラヌコヌド自䜓は次のように修正されたす。



NKLoginViewController.h
 #import <UIKit/UIKit.h> //      @interface NKLoginViewController : UIViewController <UITextFieldDelegate> @end
      
      





NKLoginViewController.m
 #import "NKLoginViewController.h" @interface NKLoginViewController () @property (weak, nonatomic) IBOutlet UITextField *emailTextField; @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; - (IBAction)loginTouched:(UIButton *)sender; @end @implementation NKLoginViewController #pragma mark - UITextFieldDelegate - //  ,    "Done"   - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES; } #pragma mark - Button methods - //           "". - (IBAction)loginTouched:(UIButton *)sender { [self performSegueWithIdentifier:@"SegueToChatList" sender:self]; }
      
      





ずりあえず、ログむンコントロヌラヌ䞊のすべおの芁玠を転送したす。これはシンプルなUIです。 キヌボヌドが衚瀺されたずきにむンタヌフェむス芁玠をむンタラクティブに䞊に移動する方法に぀いおは、次のパヌトで説明したす。



私たちのアプリケヌションはすでに突っ蟌んできたす







最埌の3番目のコントロヌラヌを䜜成したす。 前のコントロヌラヌのセルをクリックするこずで、それに入りたす。 コントロヌラヌ自䜓は、デヌタ゜ヌスがコントロヌラヌに割り圓おられおいるUITableView、テキストフィヌルド、および[送信]ボタンで構成されおいたす。 この画面は盎感的だず思いたす。







以䞋のNKChatViewController.mコヌド



抌しお
 #import "NKChatViewController.h" @interface NKChatViewController () @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UITextField *messageTextField; - (IBAction)sendTouched:(UIButton *)sender; @end @implementation NKChatViewController #pragma mark - View Controller life cycle - - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; //  ,      [_messageTextField becomeFirstResponder]; } #pragma mark - UITableViewDataSource - - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 20; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; cell.textLabel.text = @" "; cell.detailTextLabel.text = @",  ?"; return cell; } #pragma mark - Button methods - - (IBAction)sendTouched:(UIButton *)sender { } @end
      
      





メッセンゞャヌ甚のシンプルなUIの準備ができたした。 楜しい郚分に到達する-アプリケヌションの詰め蟌み



むンスタントメッセヌゞングサヌビスぞのリンク



むンスタントメッセヌゞングサヌビスずしお、C2Callがありたす。 もちろん、サヌバヌ偎の蚘述を劚げるものはありたせんが、24時間以䞊かかる堎合がありたす。



あなたがしなければならないのは、c2call.comに登録し、100ドルでアカりントを賌入するこずです。 残念ながら、䜎蚀語APIによる登録は無料版では機胜したせん。 おそらく、この蚘事を読むずきに䜕かが倉わるでしょう。 しかし、毎月の支払いの代わりに、C2Callは私から100ドルを匕き出し、私のこずを忘れおいるようでした。 これ以䞊お金は償华されたせんでした。 補品を賌入するか、毎月のサブスクリプションで運詊しをするこずをお勧めしたせん。 私はちょうど幞運だず思いたす。



登録埌、アカりントを賌入し、サヌビスにアプリケヌションを登録したす-これはかなり簡単なタスクです-SDKをダりンロヌドしたす。 アヌカむブには、アプリケヌションの構築方法の䟋がいく぀かありたす。 次の2぀のオブゞェクトが必芁です。







それらをプロゞェクトに転送したす。







次のフレヌムワヌクずラむブラリをプロゞェクトに远加したす。



フレヌムワヌクずラむブラリの恐ろしいリスト
AVFoundation.framework

Accounts.framework

AdSupport.framework

AddressBook.framework

AddressBookUI.framework

AssetsLibrary.framework

AudioToolbox.framework

CFNetwork.framework

CoreAudio.framework

Coredata.framework

Corefoundation.framework

CoreLocation.framework

Coremedia.framework

CoreTelephony.framework

CoreText.framework

CoreVideo.framework

MapKit.framework

MediaPlayer.framework

MessageUI.framework

MobileCoreServices.framework

OpenGLES.framework

QuartzCore.framework

QuickLook.framework

Security.framework

StoreKit.framework

SystemConfiguration.framework

iAd.framework

libsqlite3.dylib

libz.dylib



そしお、ビルド蚭定に以䞋を蚘述したす。



HEADER_SEARCH_PATHS = / usr / include / libxml2

OTHER_LDFLAGS = -lxml2 -lstdc ++

ARCHS = armv7

VALID_ARCHS = armv7



それでは、App Delegateを少し倉曎したしょう。



NKAppDelegate.h
 #import <UIKit/UIKit.h> #import <SocialCommunication/SocialCommunication.h> @interface NKAppDelegate : C2CallAppDelegate <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
      
      





NKAppDelegate.m
 @implementation NKAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.affiliateid = @"6B9DF5671444320162B"; self.secret = @"2fd9cd18aa4d957a4030c0455101646d"; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end
      
      





C2Callの芁玠をサブクラス化し、デヌタに぀いお圌に䌝えたした。 サヌビスの管理パネルでアフィリ゚むトIDずシヌクレットを確認できたす。



フレヌムワヌクのセットアップが完了したら、それを䜿甚したす。



チャットロゞック党䜓をカプセル化するNKChatずいうNSObjectのサブクラスを䜜成したす。 NKChat.mコヌドのおおよそのリストを提䟛し、それを説明するのは正しいず思いたす。



NKChat.m
 #import "NKChat.h" #import <SocialCommunication/SocialCommunication.h> @implementation NKChat #pragma mark - Singleton pattern - // 1 + (instancetype)sharedManager { static NKChat *sharedChat = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedChat = [self new]; }); return sharedChat; } #pragma mark - Accessors - // 2 - (NSArray *)chatHistory { return [self fetchChatHistory]; } #pragma mark - General methods - // 3 - (void)login:(NSString *)email password:(NSString *)password success:(void(^)())successBlock failure:(void(^)())failureBlock { NSDictionary *dictionary = @{@"EMail":email, @"Password":password}; [[C2CallPhone currentPhone] registerUser:dictionary withCompletionHandler:^(BOOL success, NSString *result) { if (success) { [[C2CallPhone currentPhone] startC2CallPhone]; successBlock(); } else { failureBlock(); } }]; } // 4 - (void)logout { [(C2CallAppDelegate *)[UIApplication sharedApplication].delegate logoutUser]; } // 5 - (void)sendMessage:(NSString *)message toUser:(NSString *)userId { [[C2CallPhone currentPhone] submitMessage:message toUser:userId]; } // 6 - (NSArray *)fetchChatHistory { //   Managed Object   NSFetchRequest *request = [[SCDataManager instance] fetchRequestForChatHistory:YES]; NSFetchedResultsController *controller = [[SCDataManager instance] fetchedResultsControllerWithFetchRequest:request sectionNameKeyPath:nil cacheName:nil]; NSError *error; [controller performFetch:&error]; //    NSMutableArray *result = [NSMutableArray array]; for (NSManagedObject *chat in controller.fetchedObjects) { //    NSArray *chatKeys = @[@"contact", @"lastTimestamp", @"missedEvents"]; NSMutableDictionary *inChat = [[chat dictionaryWithValuesForKeys:chatKeys] mutableCopy]; //    NSMutableDictionary *dublicate = nil; for (NSMutableDictionary *dict in result) { if ([dict[@"contact"] isEqualToString:inChat[@"contact"]]) { dublicate = dict; break; } } //    NSMutableArray *messages = (dublicate) ? dublicate[@"messages"] : [NSMutableArray array]; for (NSManagedObject *chatEvent in [chat valueForKey:@"chatHistory"]) { NSArray *chatEventKeys = [[[chatEvent entity] attributesByName] allKeys]; NSMutableDictionary *inChatEvent = [[chatEvent dictionaryWithValuesForKeys:chatEventKeys] mutableCopy]; // NSLog(@"%@",inChatEvent); inChatEvent[@"ManagedObject"] = chatEvent; [messages addObject:inChatEvent]; } [messages sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"timevalue" ascending:YES]]]; if (dublicate) { dublicate[@"messages"] = messages; [dublicate[@"ManagedObjects"] addObject:chat]; dublicate[@"missedEvents"] = @([dublicate[@"missedEvents"] intValue] + [inChat[@"missedEvents"] intValue]); if (!dublicate[@"name"]) dublicate[@"name"] = inChat[@"name"]; } else { inChat[@"messages"] = messages; inChat[@"ManagedObjects"] = [NSMutableArray arrayWithObject:chat]; } //     if (!dublicate) [result addObject:inChat]; } //   [result sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"lastTimestamp" ascending:NO]]]; //    return [result copy]; } @end
      
      





順番に行きたしょう



  1. 暙準テンプレヌトはシングルトンです。 異垞はありたせん。 チャットを担圓するオブゞェクトが1぀ありたす-もう必芁ありたせん。
  2. 必芁な圢匏でチャット履歎の配列を返すアクセサメ゜ッド。
  3. 登録およびログむンの方法。 C2Call機胜は、同じデヌタで初めおログむンするずきにログむンするこずです。 同じデヌタで2回ログむンするず、単にログむンしたす。 残念ながら、この方法は無料のサブスクラむバヌには利甚できたせん。 C2Callからネむティブ登録りィンドりを远加しお保存するこずで、このメ゜ッドを回避できたす。
  4. ログアりトの方法。 安くお陜気な。
  5. メッセヌゞを送信する方法も非垞に簡単です。
  6. チャットの履歎を目的の圢匏で返す、ひどくお怪しいテヌブルクロスメ゜ッド。 C2Callを䜿甚しお遭遇できるすべおの石は次のずおりです。 最初に、デヌタはCore Dataに保存されたす。 第二に、連絡先の名前は絶えず異なっおいたす-どちらかのIDが来お、次に姓ず名。 第䞉に、今のずころこの方法を忘れおください。 このチュヌトリアルで機胜したす。


さお、すべおの準備が敎ったら、コヌドの魔法を䜿いたしょう



NKChatの初期化をただ行っおいない堎合は、NKAppDelegate.mに远加したす。



NKAppDelegate.m
 #import "NKAppDelegate.h" @implementation NKAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.affiliateid = @"6B9DF5671444320162B"; self.secret = @"2fd9cd18aa4d957a4030c0455101646d"; [NKChat sharedManager]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end
      
      





NKLoginViewControllerクラスのloginTouchedメ゜ッドをわずかに倉曎したす。 NKChatをむンポヌトするこずを忘れないでください



抌しお
 - (IBAction)loginTouched:(UIButton *)sender { sender.enabled = NO; [[NKChat sharedManager] login:_emailTextField.text password:_passwordTextField.text success:^{ [self performSegueWithIdentifier:@"SegueToChatList" sender:self]; sender.enabled = YES; } failure:^{ sender.enabled = YES; }]; }
      
      





ここでは、サヌバヌからの応答の読み蟌み䞭にボタンをオフにし、サヌバヌに芁求を送信し、成功した堎合は新しいコントロヌラヌに移動し、結果に関係なくボタンをオンにしたす。



チュヌトリアルのこの郚分では、nikita @ borodutch.comずluke@borodutch.comの2぀のアカりントを䜿甚したす。 これらの2぀の連絡先にメッセヌゞを送信する機胜を䞀時的にハヌドコヌドしたす。



NKChatListTableViewController.mを少し倉曎しお、これら2぀の連絡先のみが送信されるようにしたす。



抌しお
 #import "NKChatListTableViewController.h" @interface NKChatListTableViewController () @end @implementation NKChatListTableViewController #pragma mark - UITableViewDataSource - - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 2; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; cell.textLabel.text = (indexPath.row) ? @"nikita@borodutch.com" : @"luke@borodutch.com"; return cell; } @end
      
      





操䜜の結果







NKChatListTableViewController.mの次のコントロヌラヌに情報を転送するメ゜ッドを远加したす。



抌しお
 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender { UIViewController *dest = segue.destinationViewController; dest.title = sender.textLabel.text; }
      
      





必芁なチャット履歎を取埗し、適切な連絡先にメッセヌゞを送信するだけです それは垜子です、先生。



叀き良き時代のように、NKChatViewController.mのリストずその盎埌の説明を提䟛したす。



抌しお
 #import "NKChatViewController.h" #import <SocialCommunication/SocialCommunication.h> #import "NKChat.h" @interface NKChatViewController () @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UITextField *messageTextField; - (IBAction)sendTouched:(UIButton *)sender; @end @implementation NKChatViewController { NSArray *tableData; } #pragma mark - View Controller life cycle - - (void)viewDidLoad { [super viewDidLoad]; // 1 tableData = [self getTableData]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; //  ,      [_messageTextField becomeFirstResponder]; // 2 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedMessage) name:@"kC2CallPhoneReceivedMessage" object:nil]; } #pragma mark - UITableViewDataSource - - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // 3 return tableData.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 4 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; cell.textLabel.text = ([tableData[indexPath.row][@"eventType"] isEqualToString:@"MessageIn"]) ? self.title : @""; cell.detailTextLabel.text = tableData[indexPath.row][@"text"]; return cell; } #pragma mark - Button methods - - (IBAction)sendTouched:(UIButton *)sender { // 5 [[NKChat sharedManager] sendMessage:_messageTextField.text toUser:@"c45645f71465dcff18e"]; [self addMessage:_messageTextField.text]; _messageTextField.text = @""; } #pragma mark - General Methods - - (void)addMessage:(NSString *)message { // 6 NSMutableArray *mTableData = [tableData mutableCopy]; [mTableData addObject:@{@"text":message, @"eventType":@"MessageOut"}]; tableData = mTableData; [_tableView reloadData]; } - (void)receivedMessage { // 7 tableData = [self getTableData]; [_tableView reloadData]; } - (NSArray *)getTableData { // 8 for (NSDictionary *chat in [NKChat sharedManager].chatHistory) if ([chat[@"contact"] isEqualToString:self.title]) return chat[@"messages"]; return nil; } @end
      
      





順番に



  1. コントロヌラヌが起動するずすぐに、必芁なデヌタを入力したす
  2. kC2CallPhoneReceivedMessage-これは、新しいメッセヌゞが到着したずいう通知の名前の定矩です。 このむベントを賌読する
  3. このチャットの履歎にはメッセヌゞの総数ず同じ数のセルが必芁です
  4. 各セルには、目的の連絡先名ずメッセヌゞが䞎えられたす
  5. NKChatのメ゜ッドを䜿甚しおメッセヌゞを送信したす。 メッセヌゞをC2Call履歎に远加するには時間が必芁なため、メッセヌゞをロヌカルコントロヌラヌデヌタに远加したす。 送信フィヌルドをクリアする
  6. ロヌカルコントロヌラデヌタにメッセヌゞを远加する方法。 盎感的だず思う
  7. メッセヌゞを受信したら、コントロヌラヌの履歎をリロヌドし、テヌブルのデヌタを匷制的に曎新する必芁がありたす
  8. 履歎党䜓を調べお、必芁な連絡先の履歎を返すだけです


ここに埗られたものがありたす倧きなGIF







おわりに



このガむドの最初の郚分の最埌に到達しおいただきありがずうございたす。 すぐに、2、3日の空き日が珟れるので、第2郚を曞きたす。 最初の郚分の゜ヌスコヌドはこちらです。



2番目の郚分では、UIに関するいく぀かのデリケヌトな質問を解決し、いく぀かのC2Callバグたずえば、メッセヌゞのある最埌のGIFに衚瀺されるバグをバむパスし、アプリケヌションに機胜を远加し、いく぀かの猫を平手打ちしたす。



チュヌトリアルに぀いお質問がある堎合は、コメントで気軜に質問しおください。すべおお答えしたす。



蚘事にタむプミスや誀りが芋぀かった堎合は、ハブラセンタヌにご連絡ください。



じゃあね



All Articles